Skip to content

Commit

Permalink
btrfs: add io_uring command for encoded reads (ENCODED_READ ioctl)
Browse files Browse the repository at this point in the history
Add an io_uring command for encoded reads, using the same interface as
the existing BTRFS_IOC_ENCODED_READ ioctl.

btrfs_uring_encoded_read() is an io_uring version of
btrfs_ioctl_encoded_read(), which validates the user input and calls
btrfs_encoded_read() to read the appropriate metadata. If we determine
that we need to read an extent from disk, we call
btrfs_encoded_read_regular_fill_pages() through
btrfs_uring_read_extent() to prepare the bio.

The existing btrfs_encoded_read_regular_fill_pages() is changed so that
if it is passed a valid uring_ctx, rather than waking up any waiting
threads it calls btrfs_uring_read_extent_endio(). This in turn copies
the read data back to userspace, and calls io_uring_cmd_done() to
complete the io_uring command.

Because we're potentially doing a non-blocking read,
btrfs_uring_read_extent() doesn't clean up after itself if it returns
-EIOCBQUEUED. Instead, it allocates a priv struct, populates the fields
there that we will need to unlock the inode and free our allocations,
and defers this to the btrfs_uring_read_finished() that gets called when
the bio completes.

Signed-off-by: Mark Harmstone <maharmstone@fb.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
maharmstone authored and kdave committed Nov 11, 2024
1 parent 68d3b27 commit 34310c4
Show file tree
Hide file tree
Showing 6 changed files with 339 additions and 12 deletions.
2 changes: 1 addition & 1 deletion fs/btrfs/btrfs_inode.h
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ int btrfs_encoded_io_compression_from_extent(struct btrfs_fs_info *fs_info,
int compress_type);
int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
u64 disk_bytenr, u64 disk_io_size,
struct page **pages);
struct page **pages, void *uring_ctx);
ssize_t btrfs_encoded_read(struct kiocb *iocb, struct iov_iter *iter,
struct btrfs_ioctl_encoded_io_args *encoded,
struct extent_state **cached_state,
Expand Down
1 change: 1 addition & 0 deletions fs/btrfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -3710,6 +3710,7 @@ const struct file_operations btrfs_file_operations = {
.compat_ioctl = btrfs_compat_ioctl,
#endif
.remap_file_range = btrfs_remap_file_range,
.uring_cmd = btrfs_uring_cmd,
.fop_flags = FOP_BUFFER_RASYNC | FOP_BUFFER_WASYNC,
};

Expand Down
41 changes: 31 additions & 10 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -9056,6 +9056,7 @@ static ssize_t btrfs_encoded_read_inline(

struct btrfs_encoded_read_private {
wait_queue_head_t wait;
void *uring_ctx;
atomic_t pending;
blk_status_t status;
};
Expand All @@ -9075,14 +9076,22 @@ 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) == 0) {
int err = blk_status_to_errno(READ_ONCE(priv->status));

if (priv->uring_ctx) {
btrfs_uring_read_extent_endio(priv->uring_ctx, err);
kfree(priv);
} else {
wake_up(&priv->wait);
}
}
bio_put(&bbio->bio);
}

int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
u64 disk_bytenr, u64 disk_io_size,
struct page **pages)
struct page **pages, void *uring_ctx)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_encoded_read_private *priv;
Expand All @@ -9097,6 +9106,7 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
init_waitqueue_head(&priv->wait);
atomic_set(&priv->pending, 1);
priv->status = 0;
priv->uring_ctx = uring_ctx;

bbio = btrfs_bio_alloc(BIO_MAX_VECS, REQ_OP_READ, fs_info,
btrfs_encoded_read_endio, priv);
Expand Down Expand Up @@ -9125,12 +9135,23 @@ int btrfs_encoded_read_regular_fill_pages(struct btrfs_inode *inode,
atomic_inc(&priv->pending);
btrfs_submit_bbio(bbio, 0);

if (atomic_dec_return(&priv->pending))
io_wait_event(priv->wait, !atomic_read(&priv->pending));
/* See btrfs_encoded_read_endio() for ordering. */
ret = blk_status_to_errno(READ_ONCE(priv->status));
kfree(priv);
return ret;
if (uring_ctx) {
if (atomic_dec_return(&priv->pending) == 0) {
ret = blk_status_to_errno(READ_ONCE(priv->status));
btrfs_uring_read_extent_endio(uring_ctx, ret);
kfree(priv);
return ret;
}

return -EIOCBQUEUED;
} else {
if (atomic_dec_return(&priv->pending) != 0)
io_wait_event(priv->wait, !atomic_read(&priv->pending));
/* See btrfs_encoded_read_endio() for ordering. */
ret = blk_status_to_errno(READ_ONCE(priv->status));
kfree(priv);
return ret;
}
}

ssize_t btrfs_encoded_read_regular(struct kiocb *iocb, struct iov_iter *iter,
Expand Down Expand Up @@ -9158,7 +9179,7 @@ ssize_t btrfs_encoded_read_regular(struct kiocb *iocb, struct iov_iter *iter,
}

ret = btrfs_encoded_read_regular_fill_pages(inode, disk_bytenr,
disk_io_size, pages);
disk_io_size, pages, NULL);
if (ret)
goto out;

Expand Down
Loading

0 comments on commit 34310c4

Please sign in to comment.