All of lore.kernel.org
 help / color / mirror / Atom feed
From: Chandan Rajendra <chandan@linux.ibm.com>
To: Eric Biggers <ebiggers@kernel.org>
Cc: linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org,
	linux-f2fs-devel@lists.sourceforge.net,
	linux-fscrypt@vger.kernel.org, tytso@mit.edu,
	adilger.kernel@dilger.ca, jaegeuk@kernel.org, yuchao0@huawei.com,
	hch@infradead.org
Subject: Re: [PATCH V2 07/13] Add decryption support for sub-pagesized blocks
Date: Wed, 01 May 2019 19:10:32 +0530	[thread overview]
Message-ID: <5473968.ZdFUMrgSOT@localhost.localdomain> (raw)
In-Reply-To: <20190430003817.GC251866@gmail.com>

Hi Eric,

On Tuesday, April 30, 2019 6:08:18 AM IST Eric Biggers wrote:
> On Sun, Apr 28, 2019 at 10:01:15AM +0530, Chandan Rajendra wrote:
> > To support decryption of sub-pagesized blocks this commit adds code to,
> > 1. Track buffer head in "struct read_callbacks_ctx".
> > 2. Pass buffer head argument to all read callbacks.
> > 3. In the corresponding endio, loop across all the blocks mapped by the
> >    page, decrypting each block in turn.
> > 
> > Signed-off-by: Chandan Rajendra <chandan@linux.ibm.com>
> > ---
> >  fs/buffer.c                    | 83 +++++++++++++++++++++++++---------
> >  fs/crypto/bio.c                | 50 +++++++++++++-------
> >  fs/crypto/crypto.c             | 19 +++++++-
> >  fs/f2fs/data.c                 |  2 +-
> >  fs/mpage.c                     |  2 +-
> >  fs/read_callbacks.c            | 53 ++++++++++++++--------
> >  include/linux/buffer_head.h    |  1 +
> >  include/linux/read_callbacks.h |  5 +-
> >  8 files changed, 154 insertions(+), 61 deletions(-)
> > 
> > diff --git a/fs/buffer.c b/fs/buffer.c
> > index ce357602f471..f324727e24bb 100644
> > --- a/fs/buffer.c
> > +++ b/fs/buffer.c
> > @@ -45,6 +45,7 @@
> >  #include <linux/bit_spinlock.h>
> >  #include <linux/pagevec.h>
> >  #include <linux/sched/mm.h>
> > +#include <linux/read_callbacks.h>
> >  #include <trace/events/block.h>
> >  
> >  static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
> > @@ -245,11 +246,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
> >  	return ret;
> >  }
> >  
> > -/*
> > - * I/O completion handler for block_read_full_page() - pages
> > - * which come unlocked at the end of I/O.
> > - */
> > -static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> > +void end_buffer_page_read(struct buffer_head *bh)
> 
> I think __end_buffer_async_read() would be a better name, since the *page* isn't
> necessarily done yet.
> 
> >  {
> >  	unsigned long flags;
> >  	struct buffer_head *first;
> > @@ -257,17 +254,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> >  	struct page *page;
> >  	int page_uptodate = 1;
> >  
> > -	BUG_ON(!buffer_async_read(bh));
> > -
> >  	page = bh->b_page;
> > -	if (uptodate) {
> > -		set_buffer_uptodate(bh);
> > -	} else {
> > -		clear_buffer_uptodate(bh);
> > -		buffer_io_error(bh, ", async page read");
> > -		SetPageError(page);
> > -	}
> > -
> >  	/*
> >  	 * Be _very_ careful from here on. Bad things can happen if
> >  	 * two buffer heads end IO at almost the same time and both
> > @@ -305,6 +292,44 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> >  	local_irq_restore(flags);
> >  	return;
> >  }
> > +EXPORT_SYMBOL(end_buffer_page_read);
> 
> No need for EXPORT_SYMBOL() here, as this is only called by built-in code.
> 
> > +
> > +/*
> > + * I/O completion handler for block_read_full_page() - pages
> > + * which come unlocked at the end of I/O.
> > + */
> 
> This comment is no longer correct.  Change to something like:
> 
> /*
>  * I/O completion handler for block_read_full_page().  Pages are unlocked after
>  * the I/O completes and the read callbacks (if any) have executed.
>  */
> 
> > +static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> > +{
> > +	struct page *page;
> > +
> > +	BUG_ON(!buffer_async_read(bh));
> > +
> > +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > +	if (uptodate && bh->b_private) {
> > +		struct read_callbacks_ctx *ctx = bh->b_private;
> > +
> > +		read_callbacks(ctx);
> > +		return;
> > +	}
> > +
> > +	if (bh->b_private) {
> > +		struct read_callbacks_ctx *ctx = bh->b_private;
> > +
> > +		WARN_ON(uptodate);
> > +		put_read_callbacks_ctx(ctx);
> > +	}
> > +#endif
> 
> These details should be handled in read_callbacks code, not here.  AFAICS, all
> you need is a function read_callbacks_end_bh() that returns a bool indicating
> whether it handled the buffer_head or not:
> 
> static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> {
> 	BUG_ON(!buffer_async_read(bh));
> 
> 	if (read_callbacks_end_bh(bh, uptodate))
> 		return;
> 
> 	page = bh->b_page;
> 	...
> }
> 
> Then read_callbacks_end_bh() would check ->b_private and uptodate, and call
> read_callbacks() or put_read_callbacks_ctx() as appropriate.  When
> CONFIG_FS_READ_CALLBACKS=n it would be a stub that always returns false.
> 
> > +	page = bh->b_page;
> [...]
> 
> >  	}
> > @@ -2292,11 +2323,21 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
> >  	 * the underlying blockdev brought it uptodate (the sct fix).
> >  	 */
> >  	for (i = 0; i < nr; i++) {
> > -		bh = arr[i];
> > -		if (buffer_uptodate(bh))
> > +		bh = arr[i].bh;
> > +		if (buffer_uptodate(bh)) {
> >  			end_buffer_async_read(bh, 1);
> > -		else
> > +		} else {
> > +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > +			struct read_callbacks_ctx *ctx;
> > +
> > +			ctx = get_read_callbacks_ctx(inode, NULL, bh, arr[i].blk_nr);
> > +			if (WARN_ON(IS_ERR(ctx))) {
> > +				end_buffer_async_read(bh, 0);
> > +				continue;
> > +			}
> > +#endif
> >  			submit_bh(REQ_OP_READ, 0, bh);
> > +		}
> >  	}
> >  	return 0;
> 
> Similarly here.  This level of detail doesn't need to be exposed outside of the
> read_callbacks code.  Just call read_callbacks_setup_bh() or something, make it
> return an 'err' rather than the read_callbacks_ctx, and make read_callbacks.h
> stub it out when !CONFIG_FS_READ_CALLBACKS.  There should be no #ifdef here.
> 
> > diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
> > index 27f5618174f2..856f4694902d 100644
> > --- a/fs/crypto/bio.c
> > +++ b/fs/crypto/bio.c
> > @@ -24,44 +24,62 @@
> >  #include <linux/module.h>
> >  #include <linux/bio.h>
> >  #include <linux/namei.h>
> > +#include <linux/buffer_head.h>
> >  #include <linux/read_callbacks.h>
> >  
> >  #include "fscrypt_private.h"
> >  
> > -static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
> > +static void fscrypt_decrypt(struct bio *bio, struct buffer_head *bh)
> >  {
> > +	struct inode *inode;
> > +	struct page *page;
> >  	struct bio_vec *bv;
> > +	sector_t blk_nr;
> > +	int ret;
> >  	int i;
> >  	struct bvec_iter_all iter_all;
> >  
> > -	bio_for_each_segment_all(bv, bio, i, iter_all) {
> > -		struct page *page = bv->bv_page;
> > -		int ret = fscrypt_decrypt_page(page->mapping->host, page,
> > -				PAGE_SIZE, 0, page->index);
> > +	WARN_ON(!bh && !bio);
> >  
> > +	if (bh) {
> > +		page = bh->b_page;
> > +		inode = page->mapping->host;
> > +
> > +		blk_nr = page->index << (PAGE_SHIFT - inode->i_blkbits);
> > +		blk_nr += (bh_offset(bh) >> inode->i_blkbits);
> > +
> > +		ret = fscrypt_decrypt_page(inode, page, i_blocksize(inode),
> > +					bh_offset(bh), blk_nr);
> >  		if (ret) {
> >  			WARN_ON_ONCE(1);
> >  			SetPageError(page);
> > -		} else if (done) {
> > -			SetPageUptodate(page);
> >  		}
> > -		if (done)
> > -			unlock_page(page);
> > +	} else if (bio) {
> > +		bio_for_each_segment_all(bv, bio, i, iter_all) {
> > +			unsigned int blkbits;
> > +
> > +			page = bv->bv_page;
> > +			inode = page->mapping->host;
> > +			blkbits = inode->i_blkbits;
> > +			blk_nr = page->index << (PAGE_SHIFT - blkbits);
> > +			blk_nr += (bv->bv_offset >> blkbits);
> > +			ret = fscrypt_decrypt_page(page->mapping->host,
> > +						page, bv->bv_len,
> > +						bv->bv_offset, blk_nr);
> > +			if (ret) {
> > +				WARN_ON_ONCE(1);
> > +				SetPageError(page);
> > +			}
> > +		}
> >  	}
> >  }
> 
> For clarity, can you make these two different functions?
> fscrypt_decrypt_bio() and fscrypt_decrypt_bh().
> 
> FYI, the WARN_ON_ONCE() here was removed in the latest fscrypt tree.
> 
> >  
> > -void fscrypt_decrypt_bio(struct bio *bio)
> > -{
> > -	__fscrypt_decrypt_bio(bio, false);
> > -}
> > -EXPORT_SYMBOL(fscrypt_decrypt_bio);
> > -
> >  void fscrypt_decrypt_work(struct work_struct *work)
> >  {
> >  	struct read_callbacks_ctx *ctx =
> >  		container_of(work, struct read_callbacks_ctx, work);
> >  
> > -	fscrypt_decrypt_bio(ctx->bio);
> > +	fscrypt_decrypt(ctx->bio, ctx->bh);
> >  
> >  	read_callbacks(ctx);
> >  }
> > diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
> > index ffa9302a7351..4f0d832cae71 100644
> > --- a/fs/crypto/crypto.c
> > +++ b/fs/crypto/crypto.c
> > @@ -305,11 +305,26 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
> >  int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
> >  			unsigned int len, unsigned int offs, u64 lblk_num)
> >  {
> > +	int i, page_nr_blks;
> > +	int err = 0;
> > +
> >  	if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
> >  		BUG_ON(!PageLocked(page));
> >  
> > -	return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
> > -				      len, offs, GFP_NOFS);
> > +	page_nr_blks = len >> inode->i_blkbits;
> > +
> > +	for (i = 0; i < page_nr_blks; i++) {
> > +		err = fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num,
> > +					page, page, i_blocksize(inode), offs,
> > +					GFP_NOFS);
> > +		if (err)
> > +			break;
> > +
> > +		++lblk_num;
> > +		offs += i_blocksize(inode);
> > +	}
> > +
> > +	return err;
> >  }
> >  EXPORT_SYMBOL(fscrypt_decrypt_page);
> 
> I was confused by the code calling this until I saw you updated it to handle
> multiple blocks.  Can you please rename it to fscrypt_decrypt_blocks()?  The
> function comment also needs to be updated to clarify what it does now (decrypt a
> contiguous sequence of one or more filesystem blocks in the page).  Also,
> 'lblk_num' should be renamed to 'starting_lblk_num' or similar.
>

fscrypt_decrypt_page() has the same semantics as fscrypt_encrypt_page()
i.e. they decrypt/encrypt contiguous blocks mapped by a page. This was the
reason behind leaving the names unchanged. Please let me know if you still think
that the names of both the functions need to be renamed to
fscrypt_[decrypt|encrypt]_blocks().

> Please also rename fscrypt_do_page_crypto() to fscrypt_crypt_block().

Sure, I will make the change.

> 
> Also, there should be a check that the len and offset are block-aligned:
> 
> 	const unsigned int blocksize = i_blocksize(inode);
> 
>         if (!IS_ALIGNED(len | offs, blocksize))
>                 return -EINVAL;
> 
> >  
> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> > index 05430d3650ab..ba437a2085e7 100644
> > --- a/fs/f2fs/data.c
> > +++ b/fs/f2fs/data.c
> > @@ -527,7 +527,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
> >  	bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
> >  
> >  #if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > -	ctx = get_read_callbacks_ctx(inode, bio, first_idx);
> > +	ctx = get_read_callbacks_ctx(inode, bio, NULL, first_idx);
> >  	if (IS_ERR(ctx)) {
> >  		bio_put(bio);
> >  		return (struct bio *)ctx;
> > diff --git a/fs/mpage.c b/fs/mpage.c
> > index e342b859ee44..0557479fdca4 100644
> > --- a/fs/mpage.c
> > +++ b/fs/mpage.c
> > @@ -348,7 +348,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
> >  			goto confused;
> >  
> >  #if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > -		ctx = get_read_callbacks_ctx(inode, args->bio, page->index);
> > +		ctx = get_read_callbacks_ctx(inode, args->bio, NULL, page->index);
> >  		if (IS_ERR(ctx)) {
> >  			bio_put(args->bio);
> >  			args->bio = NULL;
> > diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c
> > index 6dea54b0baa9..b3881c525720 100644
> > --- a/fs/read_callbacks.c
> > +++ b/fs/read_callbacks.c
> > @@ -8,6 +8,7 @@
> >  #include <linux/mm.h>
> >  #include <linux/pagemap.h>
> >  #include <linux/bio.h>
> > +#include <linux/buffer_head.h>
> >  #include <linux/fscrypt.h>
> >  #include <linux/fsverity.h>
> >  #include <linux/read_callbacks.h>
> > @@ -24,26 +25,41 @@ enum read_callbacks_step {
> >  	STEP_VERITY,
> >  };
> >  
> > -void end_read_callbacks(struct bio *bio)
> > +void end_read_callbacks(struct bio *bio, struct buffer_head *bh)
> >  {
> > +	struct read_callbacks_ctx *ctx;
> >  	struct page *page;
> >  	struct bio_vec *bv;
> >  	int i;
> >  	struct bvec_iter_all iter_all;
> >  
> > -	bio_for_each_segment_all(bv, bio, i, iter_all) {
> > -		page = bv->bv_page;
> > +	if (bh) {
> > +		if (!PageError(bh->b_page))
> > +			set_buffer_uptodate(bh);
> >  
> > -		BUG_ON(bio->bi_status);
> > +		ctx = bh->b_private;
> >  
> > -		if (!PageError(page))
> > -			SetPageUptodate(page);
> > +		end_buffer_page_read(bh);
> >  
> > -		unlock_page(page);
> > +		put_read_callbacks_ctx(ctx);
> > +	} else if (bio) {
> > +		bio_for_each_segment_all(bv, bio, i, iter_all) {
> > +			page = bv->bv_page;
> > +
> > +			WARN_ON(bio->bi_status);
> > +
> > +			if (!PageError(page))
> > +				SetPageUptodate(page);
> > +
> > +			unlock_page(page);
> > +		}
> > +		WARN_ON(!bio->bi_private);
> > +
> > +		ctx = bio->bi_private;
> > +		put_read_callbacks_ctx(ctx);
> > +
> > +		bio_put(bio);
> >  	}
> > -	if (bio->bi_private)
> > -		put_read_callbacks_ctx(bio->bi_private);
> > -	bio_put(bio);
> >  }
> >  EXPORT_SYMBOL(end_read_callbacks);
> 
> To make this easier to read, can you split this into end_read_callbacks_bio()
> and end_read_callbacks_bh()?

Sure, I will make the change.
> 
> >  
> > @@ -70,18 +86,21 @@ void read_callbacks(struct read_callbacks_ctx *ctx)
> >  		ctx->cur_step++;
> >  		/* fall-through */
> >  	default:
> > -		end_read_callbacks(ctx->bio);
> > +		end_read_callbacks(ctx->bio, ctx->bh);
> >  	}
> >  }
> >  EXPORT_SYMBOL(read_callbacks);
> >  
> >  struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
> >  						struct bio *bio,
> > +						struct buffer_head *bh,
> >  						pgoff_t index)
> >  {
> >  	unsigned int read_callbacks_steps = 0;
> >  	struct read_callbacks_ctx *ctx = NULL;
> >  
> > +	WARN_ON(!bh && !bio);
> > +
> 
> If this condition is true, return an error code; don't continue on.
> 
> >  	if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
> >  		read_callbacks_steps |= 1 << STEP_DECRYPT;
> >  #ifdef CONFIG_FS_VERITY
> > @@ -95,11 +114,15 @@ struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
> >  		ctx = mempool_alloc(read_callbacks_ctx_pool, GFP_NOFS);
> >  		if (!ctx)
> >  			return ERR_PTR(-ENOMEM);
> > +		ctx->bh = bh;
> >  		ctx->bio = bio;
> >  		ctx->inode = inode;
> >  		ctx->enabled_steps = read_callbacks_steps;
> >  		ctx->cur_step = STEP_INITIAL;
> > -		bio->bi_private = ctx;
> > +		if (bio)
> > +			bio->bi_private = ctx;
> > +		else if (bh)
> > +			bh->b_private = ctx;
> 
> ... and if doing that, then you don't need to check 'else if (bh)' here.

I agree.

> 
> >  	}
> >  	return ctx;
> >  }
> > @@ -111,12 +134,6 @@ void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx)
> >  }
> >  EXPORT_SYMBOL(put_read_callbacks_ctx);
> >  
> > -bool read_callbacks_required(struct bio *bio)
> > -{
> > -	return bio->bi_private && !bio->bi_status;
> > -}
> > -EXPORT_SYMBOL(read_callbacks_required);
> > -
> 
> It's unexpected that the patch series introduces this function,
> only to delete it later.

I had replaced bio_post_read_required() with read_callbacks_required(). I will
remove this since the requirement for post read checking will need to work for
buffer heads as well.

-- 
chandan




WARNING: multiple messages have this Message-ID (diff)
From: Chandan Rajendra <chandan@linux.ibm.com>
To: Eric Biggers <ebiggers@kernel.org>
Cc: tytso@mit.edu, linux-f2fs-devel@lists.sourceforge.net,
	hch@infradead.org, linux-fscrypt@vger.kernel.org,
	adilger.kernel@dilger.ca, linux-fsdevel@vger.kernel.org,
	jaegeuk@kernel.org, linux-ext4@vger.kernel.org
Subject: Re: [PATCH V2 07/13] Add decryption support for sub-pagesized blocks
Date: Wed, 01 May 2019 19:10:32 +0530	[thread overview]
Message-ID: <5473968.ZdFUMrgSOT@localhost.localdomain> (raw)
In-Reply-To: <20190430003817.GC251866@gmail.com>

Hi Eric,

On Tuesday, April 30, 2019 6:08:18 AM IST Eric Biggers wrote:
> On Sun, Apr 28, 2019 at 10:01:15AM +0530, Chandan Rajendra wrote:
> > To support decryption of sub-pagesized blocks this commit adds code to,
> > 1. Track buffer head in "struct read_callbacks_ctx".
> > 2. Pass buffer head argument to all read callbacks.
> > 3. In the corresponding endio, loop across all the blocks mapped by the
> >    page, decrypting each block in turn.
> > 
> > Signed-off-by: Chandan Rajendra <chandan@linux.ibm.com>
> > ---
> >  fs/buffer.c                    | 83 +++++++++++++++++++++++++---------
> >  fs/crypto/bio.c                | 50 +++++++++++++-------
> >  fs/crypto/crypto.c             | 19 +++++++-
> >  fs/f2fs/data.c                 |  2 +-
> >  fs/mpage.c                     |  2 +-
> >  fs/read_callbacks.c            | 53 ++++++++++++++--------
> >  include/linux/buffer_head.h    |  1 +
> >  include/linux/read_callbacks.h |  5 +-
> >  8 files changed, 154 insertions(+), 61 deletions(-)
> > 
> > diff --git a/fs/buffer.c b/fs/buffer.c
> > index ce357602f471..f324727e24bb 100644
> > --- a/fs/buffer.c
> > +++ b/fs/buffer.c
> > @@ -45,6 +45,7 @@
> >  #include <linux/bit_spinlock.h>
> >  #include <linux/pagevec.h>
> >  #include <linux/sched/mm.h>
> > +#include <linux/read_callbacks.h>
> >  #include <trace/events/block.h>
> >  
> >  static int fsync_buffers_list(spinlock_t *lock, struct list_head *list);
> > @@ -245,11 +246,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block)
> >  	return ret;
> >  }
> >  
> > -/*
> > - * I/O completion handler for block_read_full_page() - pages
> > - * which come unlocked at the end of I/O.
> > - */
> > -static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> > +void end_buffer_page_read(struct buffer_head *bh)
> 
> I think __end_buffer_async_read() would be a better name, since the *page* isn't
> necessarily done yet.
> 
> >  {
> >  	unsigned long flags;
> >  	struct buffer_head *first;
> > @@ -257,17 +254,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> >  	struct page *page;
> >  	int page_uptodate = 1;
> >  
> > -	BUG_ON(!buffer_async_read(bh));
> > -
> >  	page = bh->b_page;
> > -	if (uptodate) {
> > -		set_buffer_uptodate(bh);
> > -	} else {
> > -		clear_buffer_uptodate(bh);
> > -		buffer_io_error(bh, ", async page read");
> > -		SetPageError(page);
> > -	}
> > -
> >  	/*
> >  	 * Be _very_ careful from here on. Bad things can happen if
> >  	 * two buffer heads end IO at almost the same time and both
> > @@ -305,6 +292,44 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> >  	local_irq_restore(flags);
> >  	return;
> >  }
> > +EXPORT_SYMBOL(end_buffer_page_read);
> 
> No need for EXPORT_SYMBOL() here, as this is only called by built-in code.
> 
> > +
> > +/*
> > + * I/O completion handler for block_read_full_page() - pages
> > + * which come unlocked at the end of I/O.
> > + */
> 
> This comment is no longer correct.  Change to something like:
> 
> /*
>  * I/O completion handler for block_read_full_page().  Pages are unlocked after
>  * the I/O completes and the read callbacks (if any) have executed.
>  */
> 
> > +static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> > +{
> > +	struct page *page;
> > +
> > +	BUG_ON(!buffer_async_read(bh));
> > +
> > +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > +	if (uptodate && bh->b_private) {
> > +		struct read_callbacks_ctx *ctx = bh->b_private;
> > +
> > +		read_callbacks(ctx);
> > +		return;
> > +	}
> > +
> > +	if (bh->b_private) {
> > +		struct read_callbacks_ctx *ctx = bh->b_private;
> > +
> > +		WARN_ON(uptodate);
> > +		put_read_callbacks_ctx(ctx);
> > +	}
> > +#endif
> 
> These details should be handled in read_callbacks code, not here.  AFAICS, all
> you need is a function read_callbacks_end_bh() that returns a bool indicating
> whether it handled the buffer_head or not:
> 
> static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
> {
> 	BUG_ON(!buffer_async_read(bh));
> 
> 	if (read_callbacks_end_bh(bh, uptodate))
> 		return;
> 
> 	page = bh->b_page;
> 	...
> }
> 
> Then read_callbacks_end_bh() would check ->b_private and uptodate, and call
> read_callbacks() or put_read_callbacks_ctx() as appropriate.  When
> CONFIG_FS_READ_CALLBACKS=n it would be a stub that always returns false.
> 
> > +	page = bh->b_page;
> [...]
> 
> >  	}
> > @@ -2292,11 +2323,21 @@ int block_read_full_page(struct page *page, get_block_t *get_block)
> >  	 * the underlying blockdev brought it uptodate (the sct fix).
> >  	 */
> >  	for (i = 0; i < nr; i++) {
> > -		bh = arr[i];
> > -		if (buffer_uptodate(bh))
> > +		bh = arr[i].bh;
> > +		if (buffer_uptodate(bh)) {
> >  			end_buffer_async_read(bh, 1);
> > -		else
> > +		} else {
> > +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > +			struct read_callbacks_ctx *ctx;
> > +
> > +			ctx = get_read_callbacks_ctx(inode, NULL, bh, arr[i].blk_nr);
> > +			if (WARN_ON(IS_ERR(ctx))) {
> > +				end_buffer_async_read(bh, 0);
> > +				continue;
> > +			}
> > +#endif
> >  			submit_bh(REQ_OP_READ, 0, bh);
> > +		}
> >  	}
> >  	return 0;
> 
> Similarly here.  This level of detail doesn't need to be exposed outside of the
> read_callbacks code.  Just call read_callbacks_setup_bh() or something, make it
> return an 'err' rather than the read_callbacks_ctx, and make read_callbacks.h
> stub it out when !CONFIG_FS_READ_CALLBACKS.  There should be no #ifdef here.
> 
> > diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c
> > index 27f5618174f2..856f4694902d 100644
> > --- a/fs/crypto/bio.c
> > +++ b/fs/crypto/bio.c
> > @@ -24,44 +24,62 @@
> >  #include <linux/module.h>
> >  #include <linux/bio.h>
> >  #include <linux/namei.h>
> > +#include <linux/buffer_head.h>
> >  #include <linux/read_callbacks.h>
> >  
> >  #include "fscrypt_private.h"
> >  
> > -static void __fscrypt_decrypt_bio(struct bio *bio, bool done)
> > +static void fscrypt_decrypt(struct bio *bio, struct buffer_head *bh)
> >  {
> > +	struct inode *inode;
> > +	struct page *page;
> >  	struct bio_vec *bv;
> > +	sector_t blk_nr;
> > +	int ret;
> >  	int i;
> >  	struct bvec_iter_all iter_all;
> >  
> > -	bio_for_each_segment_all(bv, bio, i, iter_all) {
> > -		struct page *page = bv->bv_page;
> > -		int ret = fscrypt_decrypt_page(page->mapping->host, page,
> > -				PAGE_SIZE, 0, page->index);
> > +	WARN_ON(!bh && !bio);
> >  
> > +	if (bh) {
> > +		page = bh->b_page;
> > +		inode = page->mapping->host;
> > +
> > +		blk_nr = page->index << (PAGE_SHIFT - inode->i_blkbits);
> > +		blk_nr += (bh_offset(bh) >> inode->i_blkbits);
> > +
> > +		ret = fscrypt_decrypt_page(inode, page, i_blocksize(inode),
> > +					bh_offset(bh), blk_nr);
> >  		if (ret) {
> >  			WARN_ON_ONCE(1);
> >  			SetPageError(page);
> > -		} else if (done) {
> > -			SetPageUptodate(page);
> >  		}
> > -		if (done)
> > -			unlock_page(page);
> > +	} else if (bio) {
> > +		bio_for_each_segment_all(bv, bio, i, iter_all) {
> > +			unsigned int blkbits;
> > +
> > +			page = bv->bv_page;
> > +			inode = page->mapping->host;
> > +			blkbits = inode->i_blkbits;
> > +			blk_nr = page->index << (PAGE_SHIFT - blkbits);
> > +			blk_nr += (bv->bv_offset >> blkbits);
> > +			ret = fscrypt_decrypt_page(page->mapping->host,
> > +						page, bv->bv_len,
> > +						bv->bv_offset, blk_nr);
> > +			if (ret) {
> > +				WARN_ON_ONCE(1);
> > +				SetPageError(page);
> > +			}
> > +		}
> >  	}
> >  }
> 
> For clarity, can you make these two different functions?
> fscrypt_decrypt_bio() and fscrypt_decrypt_bh().
> 
> FYI, the WARN_ON_ONCE() here was removed in the latest fscrypt tree.
> 
> >  
> > -void fscrypt_decrypt_bio(struct bio *bio)
> > -{
> > -	__fscrypt_decrypt_bio(bio, false);
> > -}
> > -EXPORT_SYMBOL(fscrypt_decrypt_bio);
> > -
> >  void fscrypt_decrypt_work(struct work_struct *work)
> >  {
> >  	struct read_callbacks_ctx *ctx =
> >  		container_of(work, struct read_callbacks_ctx, work);
> >  
> > -	fscrypt_decrypt_bio(ctx->bio);
> > +	fscrypt_decrypt(ctx->bio, ctx->bh);
> >  
> >  	read_callbacks(ctx);
> >  }
> > diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c
> > index ffa9302a7351..4f0d832cae71 100644
> > --- a/fs/crypto/crypto.c
> > +++ b/fs/crypto/crypto.c
> > @@ -305,11 +305,26 @@ EXPORT_SYMBOL(fscrypt_encrypt_page);
> >  int fscrypt_decrypt_page(const struct inode *inode, struct page *page,
> >  			unsigned int len, unsigned int offs, u64 lblk_num)
> >  {
> > +	int i, page_nr_blks;
> > +	int err = 0;
> > +
> >  	if (!(inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES))
> >  		BUG_ON(!PageLocked(page));
> >  
> > -	return fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num, page, page,
> > -				      len, offs, GFP_NOFS);
> > +	page_nr_blks = len >> inode->i_blkbits;
> > +
> > +	for (i = 0; i < page_nr_blks; i++) {
> > +		err = fscrypt_do_page_crypto(inode, FS_DECRYPT, lblk_num,
> > +					page, page, i_blocksize(inode), offs,
> > +					GFP_NOFS);
> > +		if (err)
> > +			break;
> > +
> > +		++lblk_num;
> > +		offs += i_blocksize(inode);
> > +	}
> > +
> > +	return err;
> >  }
> >  EXPORT_SYMBOL(fscrypt_decrypt_page);
> 
> I was confused by the code calling this until I saw you updated it to handle
> multiple blocks.  Can you please rename it to fscrypt_decrypt_blocks()?  The
> function comment also needs to be updated to clarify what it does now (decrypt a
> contiguous sequence of one or more filesystem blocks in the page).  Also,
> 'lblk_num' should be renamed to 'starting_lblk_num' or similar.
>

fscrypt_decrypt_page() has the same semantics as fscrypt_encrypt_page()
i.e. they decrypt/encrypt contiguous blocks mapped by a page. This was the
reason behind leaving the names unchanged. Please let me know if you still think
that the names of both the functions need to be renamed to
fscrypt_[decrypt|encrypt]_blocks().

> Please also rename fscrypt_do_page_crypto() to fscrypt_crypt_block().

Sure, I will make the change.

> 
> Also, there should be a check that the len and offset are block-aligned:
> 
> 	const unsigned int blocksize = i_blocksize(inode);
> 
>         if (!IS_ALIGNED(len | offs, blocksize))
>                 return -EINVAL;
> 
> >  
> > diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
> > index 05430d3650ab..ba437a2085e7 100644
> > --- a/fs/f2fs/data.c
> > +++ b/fs/f2fs/data.c
> > @@ -527,7 +527,7 @@ static struct bio *f2fs_grab_read_bio(struct inode *inode, block_t blkaddr,
> >  	bio_set_op_attrs(bio, REQ_OP_READ, op_flag);
> >  
> >  #if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > -	ctx = get_read_callbacks_ctx(inode, bio, first_idx);
> > +	ctx = get_read_callbacks_ctx(inode, bio, NULL, first_idx);
> >  	if (IS_ERR(ctx)) {
> >  		bio_put(bio);
> >  		return (struct bio *)ctx;
> > diff --git a/fs/mpage.c b/fs/mpage.c
> > index e342b859ee44..0557479fdca4 100644
> > --- a/fs/mpage.c
> > +++ b/fs/mpage.c
> > @@ -348,7 +348,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args)
> >  			goto confused;
> >  
> >  #if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY)
> > -		ctx = get_read_callbacks_ctx(inode, args->bio, page->index);
> > +		ctx = get_read_callbacks_ctx(inode, args->bio, NULL, page->index);
> >  		if (IS_ERR(ctx)) {
> >  			bio_put(args->bio);
> >  			args->bio = NULL;
> > diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c
> > index 6dea54b0baa9..b3881c525720 100644
> > --- a/fs/read_callbacks.c
> > +++ b/fs/read_callbacks.c
> > @@ -8,6 +8,7 @@
> >  #include <linux/mm.h>
> >  #include <linux/pagemap.h>
> >  #include <linux/bio.h>
> > +#include <linux/buffer_head.h>
> >  #include <linux/fscrypt.h>
> >  #include <linux/fsverity.h>
> >  #include <linux/read_callbacks.h>
> > @@ -24,26 +25,41 @@ enum read_callbacks_step {
> >  	STEP_VERITY,
> >  };
> >  
> > -void end_read_callbacks(struct bio *bio)
> > +void end_read_callbacks(struct bio *bio, struct buffer_head *bh)
> >  {
> > +	struct read_callbacks_ctx *ctx;
> >  	struct page *page;
> >  	struct bio_vec *bv;
> >  	int i;
> >  	struct bvec_iter_all iter_all;
> >  
> > -	bio_for_each_segment_all(bv, bio, i, iter_all) {
> > -		page = bv->bv_page;
> > +	if (bh) {
> > +		if (!PageError(bh->b_page))
> > +			set_buffer_uptodate(bh);
> >  
> > -		BUG_ON(bio->bi_status);
> > +		ctx = bh->b_private;
> >  
> > -		if (!PageError(page))
> > -			SetPageUptodate(page);
> > +		end_buffer_page_read(bh);
> >  
> > -		unlock_page(page);
> > +		put_read_callbacks_ctx(ctx);
> > +	} else if (bio) {
> > +		bio_for_each_segment_all(bv, bio, i, iter_all) {
> > +			page = bv->bv_page;
> > +
> > +			WARN_ON(bio->bi_status);
> > +
> > +			if (!PageError(page))
> > +				SetPageUptodate(page);
> > +
> > +			unlock_page(page);
> > +		}
> > +		WARN_ON(!bio->bi_private);
> > +
> > +		ctx = bio->bi_private;
> > +		put_read_callbacks_ctx(ctx);
> > +
> > +		bio_put(bio);
> >  	}
> > -	if (bio->bi_private)
> > -		put_read_callbacks_ctx(bio->bi_private);
> > -	bio_put(bio);
> >  }
> >  EXPORT_SYMBOL(end_read_callbacks);
> 
> To make this easier to read, can you split this into end_read_callbacks_bio()
> and end_read_callbacks_bh()?

Sure, I will make the change.
> 
> >  
> > @@ -70,18 +86,21 @@ void read_callbacks(struct read_callbacks_ctx *ctx)
> >  		ctx->cur_step++;
> >  		/* fall-through */
> >  	default:
> > -		end_read_callbacks(ctx->bio);
> > +		end_read_callbacks(ctx->bio, ctx->bh);
> >  	}
> >  }
> >  EXPORT_SYMBOL(read_callbacks);
> >  
> >  struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
> >  						struct bio *bio,
> > +						struct buffer_head *bh,
> >  						pgoff_t index)
> >  {
> >  	unsigned int read_callbacks_steps = 0;
> >  	struct read_callbacks_ctx *ctx = NULL;
> >  
> > +	WARN_ON(!bh && !bio);
> > +
> 
> If this condition is true, return an error code; don't continue on.
> 
> >  	if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode))
> >  		read_callbacks_steps |= 1 << STEP_DECRYPT;
> >  #ifdef CONFIG_FS_VERITY
> > @@ -95,11 +114,15 @@ struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode,
> >  		ctx = mempool_alloc(read_callbacks_ctx_pool, GFP_NOFS);
> >  		if (!ctx)
> >  			return ERR_PTR(-ENOMEM);
> > +		ctx->bh = bh;
> >  		ctx->bio = bio;
> >  		ctx->inode = inode;
> >  		ctx->enabled_steps = read_callbacks_steps;
> >  		ctx->cur_step = STEP_INITIAL;
> > -		bio->bi_private = ctx;
> > +		if (bio)
> > +			bio->bi_private = ctx;
> > +		else if (bh)
> > +			bh->b_private = ctx;
> 
> ... and if doing that, then you don't need to check 'else if (bh)' here.

I agree.

> 
> >  	}
> >  	return ctx;
> >  }
> > @@ -111,12 +134,6 @@ void put_read_callbacks_ctx(struct read_callbacks_ctx *ctx)
> >  }
> >  EXPORT_SYMBOL(put_read_callbacks_ctx);
> >  
> > -bool read_callbacks_required(struct bio *bio)
> > -{
> > -	return bio->bi_private && !bio->bi_status;
> > -}
> > -EXPORT_SYMBOL(read_callbacks_required);
> > -
> 
> It's unexpected that the patch series introduces this function,
> only to delete it later.

I had replaced bio_post_read_required() with read_callbacks_required(). I will
remove this since the requirement for post read checking will need to work for
buffer heads as well.

-- 
chandan

  reply	other threads:[~2019-05-01 14:24 UTC|newest]

Thread overview: 74+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-04-28  4:31 [PATCH V2 00/13] Consolidate FS read I/O callbacks code Chandan Rajendra
2019-04-28  4:31 ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 01/13] ext4: Clear BH_Uptodate flag on decryption error Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 02/13] Consolidate "read callbacks" into a new file Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30  0:00   ` Eric Biggers
2019-04-30  0:00     ` [f2fs-dev] " Eric Biggers
2019-04-30  0:00     ` Eric Biggers
2019-05-01 12:30     ` Chandan Rajendra
2019-05-01 12:30       ` Chandan Rajendra
2019-04-30  1:37   ` Chao Yu
2019-04-30  1:37     ` Chao Yu
2019-04-30  1:37     ` Chao Yu
2019-05-01 12:31     ` Chandan Rajendra
2019-05-01 12:31       ` Chandan Rajendra
2019-04-30 18:05   ` Eric Biggers
2019-04-30 18:05     ` [f2fs-dev] " Eric Biggers
2019-04-30 18:05     ` Eric Biggers
2019-05-01 12:32     ` Chandan Rajendra
2019-05-01 12:32       ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 03/13] fsverity: Add call back to decide if verity check has to be performed Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30 21:10   ` Jeremy Sowden
2019-05-01 12:33     ` Chandan Rajendra
2019-05-01 12:33       ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 04/13] fsverity: Add call back to determine readpage limit Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 05/13] fs/mpage.c: Integrate read callbacks Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 06/13] ext4: Wire up ext4_readpage[s] to use mpage_readpage[s] Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 07/13] Add decryption support for sub-pagesized blocks Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30  0:38   ` Eric Biggers
2019-04-30  0:38     ` [f2fs-dev] " Eric Biggers
2019-04-30  0:38     ` Eric Biggers
2019-05-01 13:40     ` Chandan Rajendra [this message]
2019-05-01 13:40       ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 08/13] ext4: Decrypt all boundary blocks when doing buffered write Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 09/13] ext4: Decrypt the block that needs to be partially zeroed Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 10/13] fscrypt_encrypt_page: Loop across all blocks mapped by a page range Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30 17:11   ` Eric Biggers
2019-04-30 17:11     ` [f2fs-dev] " Eric Biggers
2019-04-30 17:11     ` Eric Biggers
2019-04-30 23:08     ` [f2fs-dev] " Eric Biggers
2019-04-30 23:08       ` Eric Biggers
2019-05-01 14:49       ` [f2fs-dev] " Chandan Rajendra
2019-05-01 14:49         ` Chandan Rajendra
2019-05-01 22:29         ` [f2fs-dev] " Eric Biggers
2019-05-01 22:29           ` Eric Biggers
2019-05-02  5:52           ` [f2fs-dev] " Chandan Rajendra
2019-05-02  5:52             ` Chandan Rajendra
2019-05-02 18:16             ` [f2fs-dev] " Eric Biggers
2019-05-02 18:16               ` Eric Biggers
2019-04-28  4:31 ` [PATCH V2 11/13] ext4: Compute logical block and the page range to be encrypted Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30 17:01   ` Eric Biggers
2019-04-30 17:01     ` Eric Biggers
2019-05-01 14:11     ` Chandan Rajendra
2019-05-01 14:11       ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 12/13] fscrypt_zeroout_range: Encrypt all zeroed out blocks of a page Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30 16:51   ` Eric Biggers
2019-04-30 16:51     ` Eric Biggers
2019-05-01 14:22     ` Chandan Rajendra
2019-05-01 14:22       ` Chandan Rajendra
2019-04-28  4:31 ` [PATCH V2 13/13] ext4: Enable encryption for subpage-sized blocks Chandan Rajendra
2019-04-28  4:31   ` Chandan Rajendra
2019-04-30  0:27 ` [PATCH V2 00/13] Consolidate FS read I/O callbacks code Matthew Wilcox
2019-04-30  0:27   ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5473968.ZdFUMrgSOT@localhost.localdomain \
    --to=chandan@linux.ibm.com \
    --cc=adilger.kernel@dilger.ca \
    --cc=ebiggers@kernel.org \
    --cc=hch@infradead.org \
    --cc=jaegeuk@kernel.org \
    --cc=linux-ext4@vger.kernel.org \
    --cc=linux-f2fs-devel@lists.sourceforge.net \
    --cc=linux-fscrypt@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=tytso@mit.edu \
    --cc=yuchao0@huawei.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.