diff mbox series

[2/5] btrfs: change btrfs_encoded_read_regular_fill_pages to take a callback

Message ID 20241014171838.304953-3-maharmstone@fb.com (mailing list archive)
State New
Headers show
Series btrfs: encoded reads via io_uring | expand

Commit Message

Mark Harmstone Oct. 14, 2024, 5:18 p.m. UTC
Change btrfs_encoded_read_regular_fill_pages so that it takes a callback
rather than waiting, and add new helper function btrfs_encoded_read_wait_cb
to match the existing behaviour.

Signed-off-by: Mark Harmstone <maharmstone@fb.com>
---
 fs/btrfs/btrfs_inode.h | 13 +++++++-
 fs/btrfs/inode.c       | 70 ++++++++++++++++++++++++++++++++----------
 fs/btrfs/send.c        | 15 ++++++++-
 3 files changed, 79 insertions(+), 19 deletions(-)

Comments

David Sterba Oct. 15, 2024, 3:23 p.m. UTC | #1
On Mon, Oct 14, 2024 at 06:18:24PM +0100, Mark Harmstone wrote:
> Change btrfs_encoded_read_regular_fill_pages so that it takes a callback
> rather than waiting, and add new helper function btrfs_encoded_read_wait_cb
> to match the existing behaviour.

Please avoid callbacks and function pointers when it's in the same
subsystem. Pass some enum and do a switch inside the function, or wrap
it to a helper if needed. Since spectre/meltdown function pointers in
kernel have been removed when possible and I don't see a strong reason
for it here.
David Sterba Oct. 21, 2024, 1:21 p.m. UTC | #2
On Mon, Oct 14, 2024 at 06:18:24PM +0100, Mark Harmstone wrote:
> Change btrfs_encoded_read_regular_fill_pages so that it takes a callback
> rather than waiting, and add new helper function btrfs_encoded_read_wait_cb
> to match the existing behaviour.
> 
> Signed-off-by: Mark Harmstone <maharmstone@fb.com>
> ---
>  fs/btrfs/btrfs_inode.h | 13 +++++++-
>  fs/btrfs/inode.c       | 70 ++++++++++++++++++++++++++++++++----------
>  fs/btrfs/send.c        | 15 ++++++++-
>  3 files changed, 79 insertions(+), 19 deletions(-)
> 
> diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
> index 3056c8aed8ef..6aea5bedc968 100644
> --- a/fs/btrfs/btrfs_inode.h
> +++ b/fs/btrfs/btrfs_inode.h
> @@ -601,10 +601,21 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
>  int btrfs_writepage_cow_fixup(struct page *page);
>  int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
>  					     int compress_type);
> +typedef void (btrfs_encoded_read_cb_t)(void *, int);
> +
> +struct btrfs_encoded_read_wait_ctx {
> +	wait_queue_head_t wait;
> +	bool done;
> +	int err;

Please reorder that so it does not waste the bytes after 'done' to align
'err'

> +};
> +
> +void btrfs_encoded_read_wait_cb(void *ctx, int err);
>  int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
>  					  u64 file_offset, u64 disk_bytenr,
>  					  u64 disk_io_size,
> -					  struct page **pages);
> +					  struct page **pages,
> +					  btrfs_encoded_read_cb_t cb,
> +					  void *cb_ctx);
>  ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
>  			   struct btrfs_ioctl_encoded_io_args *encoded);
>  ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index b024ebc3dcd6..b5abe98f3af4 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -9080,9 +9080,10 @@ static ssize_t btrfs_encoded_read_inline(
>  }
>  
>  struct btrfs_encoded_read_private {
> -	wait_queue_head_t wait;
>  	atomic_t pending;
>  	blk_status_t status;
> +	btrfs_encoded_read_cb_t *cb;
> +	void *cb_ctx;

Final version of this structure could be also reordered so it does not
leave unnecessary holes, I think status is u8 so it now fills the hole
after pending but I'm not sure now if other patches make more changes.

>  };
>  
>  static void btrfs_encoded_read_endio(struct btrfs_bio *bbio)
> @@ -9100,26 +9101,33 @@ static void btrfs_encoded_read_endio(struct btrfs_bio *bbio)
>  		 */
>  		WRITE_ONCE(priv->status, bbio->bio.bi_status);
>  	}
> -	if (!atomic_dec_return(&priv->pending))
> -		wake_up(&priv->wait);
> +	if (!atomic_dec_return(&priv->pending)) {

Though it's in the original code, please rewrite the condition so it
reads as an arithmetic condition, "== 0".

> +		priv->cb(priv->cb_ctx,
> +			 blk_status_to_errno(READ_ONCE(priv->status)));
> +		kfree(priv);
> +	}
>  	bio_put(&bbio->bio);
>  }
diff mbox series

Patch

diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index 3056c8aed8ef..6aea5bedc968 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -601,10 +601,21 @@  int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
 int btrfs_writepage_cow_fixup(struct page *page);
 int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
 					     int compress_type);
+typedef void (btrfs_encoded_read_cb_t)(void *, int);
+
+struct btrfs_encoded_read_wait_ctx {
+	wait_queue_head_t wait;
+	bool done;
+	int err;
+};
+
+void btrfs_encoded_read_wait_cb(void *ctx, int err);
 int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
 					  u64 file_offset, u64 disk_bytenr,
 					  u64 disk_io_size,
-					  struct page **pages);
+					  struct page **pages,
+					  btrfs_encoded_read_cb_t cb,
+					  void *cb_ctx);
 ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
 			   struct btrfs_ioctl_encoded_io_args *encoded);
 ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b024ebc3dcd6..b5abe98f3af4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9080,9 +9080,10 @@  static ssize_t btrfs_encoded_read_inline(
 }
 
 struct btrfs_encoded_read_private {
-	wait_queue_head_t wait;
 	atomic_t pending;
 	blk_status_t status;
+	btrfs_encoded_read_cb_t *cb;
+	void *cb_ctx;
 };
 
 static void btrfs_encoded_read_endio(struct btrfs_bio *bbio)
@@ -9100,26 +9101,33 @@  static void btrfs_encoded_read_endio(struct btrfs_bio *bbio)
 		 */
 		WRITE_ONCE(priv->status, bbio->bio.bi_status);
 	}
-	if (!atomic_dec_return(&priv->pending))
-		wake_up(&priv->wait);
+	if (!atomic_dec_return(&priv->pending)) {
+		priv->cb(priv->cb_ctx,
+			 blk_status_to_errno(READ_ONCE(priv->status)));
+		kfree(priv);
+	}
 	bio_put(&bbio->bio);
 }
 
 int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
 					  u64 file_offset, u64 disk_bytenr,
-					  u64 disk_io_size, struct page **pages)
+					  u64 disk_io_size, struct page **pages,
+					  btrfs_encoded_read_cb_t cb,
+					  void *cb_ctx)
 {
 	struct btrfs_fs_info *fs_info = inode->root->fs_info;
-	struct btrfs_encoded_read_private priv = {
-		.pending = ATOMIC_INIT(1),
-	};
+	struct btrfs_encoded_read_private *priv;
 	unsigned long i = 0;
 	struct btrfs_bio *bbio;
 
-	init_waitqueue_head(&priv.wait);
+	priv = kmalloc(sizeof(struct btrfs_encoded_read_private), GFP_NOFS);
+	if (!priv)
+		return -ENOMEM;
+
+	atomic_set(&priv->pending, 1);
 
 	bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, fs_info,
-			       btrfs_encoded_read_endio, &priv);
+			       btrfs_encoded_read_endio, priv);
 	bbio->bio.bi_iter.bi_sector = disk_bytenr >> SECTOR_SHIFT;
 	bbio->inode = inode;
 
@@ -9127,11 +9135,11 @@  int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
 		size_t bytes = min_t(u64, disk_io_size, PAGE_SIZE);
 
 		if (bio_add_page(&bbio->bio, pages[i], bytes, 0) < bytes) {
-			atomic_inc(&priv.pending);
+			atomic_inc(&priv->pending);
 			btrfs_submit_bio(bbio, 0);
 
 			bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, fs_info,
-					       btrfs_encoded_read_endio, &priv);
+					       btrfs_encoded_read_endio, priv);
 			bbio->bio.bi_iter.bi_sector = disk_bytenr >> SECTOR_SHIFT;
 			bbio->inode = inode;
 			continue;
@@ -9142,13 +9150,28 @@  int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
 		disk_io_size -= bytes;
 	} while (disk_io_size);
 
-	atomic_inc(&priv.pending);
+	atomic_inc(&priv->pending);
+	priv->cb = cb;
+	priv->cb_ctx = cb_ctx;
+
 	btrfs_submit_bio(bbio, 0);
 
-	if (atomic_dec_return(&priv.pending))
-		io_wait_event(priv.wait, !atomic_read(&priv.pending));
-	/* See btrfs_encoded_read_endio() for ordering. */
-	return blk_status_to_errno(READ_ONCE(priv.status));
+	if (!atomic_dec_return(&priv->pending)) {
+		cb(cb_ctx, blk_status_to_errno(READ_ONCE(priv->status)));
+		kfree(priv);
+	}
+
+	return 0;
+}
+
+void btrfs_encoded_read_wait_cb(void *ctx, int err)
+{
+	struct btrfs_encoded_read_wait_ctx *priv = ctx;
+
+	priv->err = err;
+	priv->done = true;
+
+	wake_up(&priv->wait);
 }
 
 static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
@@ -9166,6 +9189,7 @@  static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
 	u64 cur;
 	size_t page_offset;
 	ssize_t ret;
+	struct btrfs_encoded_read_wait_ctx wait_ctx;
 
 	nr_pages = DIV_ROUND_UP(disk_io_size, PAGE_SIZE);
 	pages = kcalloc(nr_pages, sizeof(struct page *), GFP_NOFS);
@@ -9177,11 +9201,23 @@  static ssize_t btrfs_encoded_read_regular(struct kiocb *iocb,
 		goto out;
 		}
 
+	wait_ctx.done = false;
+	init_waitqueue_head(&wait_ctx.wait);
+
 	ret = btrfs_encoded_read_regular_fill_pages(inode, start, disk_bytenr,
-						    disk_io_size, pages);
+						    disk_io_size, pages,
+						    btrfs_encoded_read_wait_cb,
+						    &wait_ctx);
 	if (ret)
 		goto out;
 
+	io_wait_event(wait_ctx.wait, wait_ctx.done);
+
+	if (wait_ctx.err) {
+		ret = wait_ctx.err;
+		goto out;
+	}
+
 	unlock_extent(io_tree, start, lockend, cached_state);
 	btrfs_inode_unlock(inode, BTRFS_ILOCK_SHARED);
 	*unlocked = true;
diff --git a/fs/btrfs/send.c b/fs/btrfs/send.c
index 619fa0b8b3f6..52f653c6671e 100644
--- a/fs/btrfs/send.c
+++ b/fs/btrfs/send.c
@@ -5613,6 +5613,7 @@  static int send_encoded_extent(struct send_ctx *sctx, struct btrfs_path *path,
 	u64 disk_bytenr, disk_num_bytes;
 	u32 data_offset;
 	struct btrfs_cmd_header *hdr;
+	struct btrfs_encoded_read_wait_ctx wait_ctx;
 	u32 crc;
 	int ret;
 
@@ -5671,6 +5672,9 @@  static int send_encoded_extent(struct send_ctx *sctx, struct btrfs_path *path,
 		goto out;
 	}
 
+	wait_ctx.done = false;
+	init_waitqueue_head(&wait_ctx.wait);
+
 	/*
 	 * Note that send_buf is a mapping of send_buf_pages, so this is really
 	 * reading into send_buf.
@@ -5678,10 +5682,19 @@  static int send_encoded_extent(struct send_ctx *sctx, struct btrfs_path *path,
 	ret = btrfs_encoded_read_regular_fill_pages(BTRFS_I(inode), offset,
 						    disk_bytenr, disk_num_bytes,
 						    sctx->send_buf_pages +
-						    (data_offset >> PAGE_SHIFT));
+						    (data_offset >> PAGE_SHIFT),
+						    btrfs_encoded_read_wait_cb,
+						    &wait_ctx);
 	if (ret)
 		goto out;
 
+	io_wait_event(wait_ctx.wait, wait_ctx.done);
+
+	if (wait_ctx.err) {
+		ret = wait_ctx.err;
+		goto out;
+	}
+
 	hdr = (struct btrfs_cmd_header *)sctx->send_buf;
 	hdr->len = cpu_to_le32(sctx->send_size + disk_num_bytes - sizeof(*hdr));
 	hdr->crc = 0;