* Re: [PATCH] btrfs: add io_uring interface for encoded reads
[not found] <[email protected]>
@ 2024-08-12 11:26 ` Christoph Hellwig
2024-08-12 14:46 ` Mark Harmstone
2024-08-12 16:10 ` Pavel Begunkov
0 siblings, 2 replies; 8+ messages in thread
From: Christoph Hellwig @ 2024-08-12 11:26 UTC (permalink / raw)
To: Mark Harmstone; +Cc: linux-btrfs, Jens Axboe, Pavel Begunkov, io-uring
On Fri, Aug 09, 2024 at 06:35:27PM +0100, Mark Harmstone wrote:
> Adds an io_uring interface for asynchronous encoded reads, using the
> same interface as for the ioctl. To use this you would use an SQE opcode
> of IORING_OP_URING_CMD, the cmd_op would be BTRFS_IOC_ENCODED_READ, and
> addr would point to the userspace address of the
> btrfs_ioctl_encoded_io_args struct. As with the ioctl, you need to have
> CAP_SYS_ADMIN for this to work.
What is the point if this doesn't actually do anything but returning
-EIOCBQUEUED?
Note that that the internals of the btrfs encoded read is built
around kiocbs anyway, so you might as well turn things upside down,
implement a real async io_uring cmd and just wait for it to complete
to implement the existing synchronous ioctl.
>
> Signed-off-by: Mark Harmstone <[email protected]>
> ---
> fs/btrfs/file.c | 1 +
> fs/btrfs/ioctl.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
> fs/btrfs/ioctl.h | 1 +
> 3 files changed, 50 insertions(+)
>
> diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
> index f9d76072398d..974f9e85b46e 100644
> --- a/fs/btrfs/file.c
> +++ b/fs/btrfs/file.c
> @@ -3850,6 +3850,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,
> };
>
> int btrfs_fdatawrite_range(struct inode *inode, loff_t start, loff_t end)
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 0493272a7668..8f5cc7d1429c 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -29,6 +29,7 @@
> #include <linux/fileattr.h>
> #include <linux/fsverity.h>
> #include <linux/sched/xacct.h>
> +#include <linux/io_uring/cmd.h>
> #include "ctree.h"
> #include "disk-io.h"
> #include "export.h"
> @@ -4648,6 +4649,53 @@ static int btrfs_ioctl_encoded_write(struct file *file, void __user *argp, bool
> return ret;
> }
>
> +static void btrfs_uring_encoded_read_cb(struct io_uring_cmd *cmd,
> + unsigned int issue_flags)
> +{
> + int ret;
> +
> + ret = btrfs_ioctl_encoded_read(cmd->file, (void __user *)cmd->sqe->addr,
> + false);
> +
> + io_uring_cmd_done(cmd, ret, 0, issue_flags);
> +}
> +
> +static void btrfs_uring_encoded_read_compat_cb(struct io_uring_cmd *cmd,
> + unsigned int issue_flags)
> +{
> + int ret;
> +
> + ret = btrfs_ioctl_encoded_read(cmd->file, (void __user *)cmd->sqe->addr,
> + true);
> +
> + io_uring_cmd_done(cmd, ret, 0, issue_flags);
> +}
> +
> +static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd,
> + unsigned int issue_flags)
> +{
> + if (issue_flags & IO_URING_F_COMPAT)
> + io_uring_cmd_complete_in_task(cmd, btrfs_uring_encoded_read_compat_cb);
> + else
> + io_uring_cmd_complete_in_task(cmd, btrfs_uring_encoded_read_cb);
> +
> + return -EIOCBQUEUED;
> +}
> +
> +int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
> +{
> + switch (cmd->cmd_op) {
> + case BTRFS_IOC_ENCODED_READ:
> +#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
> + case BTRFS_IOC_ENCODED_READ_32:
> +#endif
> + return btrfs_uring_encoded_read(cmd, issue_flags);
> + }
> +
> + io_uring_cmd_done(cmd, -EINVAL, 0, issue_flags);
> + return -EIOCBQUEUED;
> +}
> +
> long btrfs_ioctl(struct file *file, unsigned int
> cmd, unsigned long arg)
> {
> diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
> index 2c5dc25ec670..33578f4b5f46 100644
> --- a/fs/btrfs/ioctl.h
> +++ b/fs/btrfs/ioctl.h
> @@ -22,5 +22,6 @@ void btrfs_sync_inode_flags_to_i_flags(struct inode *inode);
> int __pure btrfs_is_empty_uuid(u8 *uuid);
> void btrfs_update_ioctl_balance_args(struct btrfs_fs_info *fs_info,
> struct btrfs_ioctl_balance_args *bargs);
> +int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags);
>
> #endif
> --
> 2.44.2
>
>
---end quoted text---
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 11:26 ` [PATCH] btrfs: add io_uring interface for encoded reads Christoph Hellwig
@ 2024-08-12 14:46 ` Mark Harmstone
2024-08-12 15:03 ` Pavel Begunkov
2024-08-12 16:10 ` Pavel Begunkov
1 sibling, 1 reply; 8+ messages in thread
From: Mark Harmstone @ 2024-08-12 14:46 UTC (permalink / raw)
To: Christoph Hellwig
Cc: [email protected], Jens Axboe, Pavel Begunkov,
[email protected]
On 12/8/24 12:26, Christoph Hellwig wrote:
> What is the point if this doesn't actually do anything but returning
> -EIOCBQUEUED?
It returns EIOCBQUEUED to say that io_uring has queued the request, and
adds the task to io_uring's thread pool for it to be completed.
> Note that that the internals of the btrfs encoded read is built
> around kiocbs anyway, so you might as well turn things upside down,
> implement a real async io_uring cmd and just wait for it to complete
> to implement the existing synchronous ioctl.
I'd have to look into it, but that sounds like it could be an
interesting future refactor.
Mark
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 14:46 ` Mark Harmstone
@ 2024-08-12 15:03 ` Pavel Begunkov
0 siblings, 0 replies; 8+ messages in thread
From: Pavel Begunkov @ 2024-08-12 15:03 UTC (permalink / raw)
To: Mark Harmstone, Christoph Hellwig
Cc: [email protected], Jens Axboe, [email protected]
On 8/12/24 15:46, Mark Harmstone wrote:
> On 12/8/24 12:26, Christoph Hellwig wrote:
>> What is the point if this doesn't actually do anything but returning
>> -EIOCBQUEUED?
>
> It returns EIOCBQUEUED to say that io_uring has queued the request, and
> adds the task to io_uring's thread pool for it to be completed.
No, it doesn't. With your patch it'll be executed by the
task submitting the request and seemingly get blocked,
which is not how an async interface can work.
I'll comment on the main patch.
>> Note that that the internals of the btrfs encoded read is built
>> around kiocbs anyway, so you might as well turn things upside down,
>> implement a real async io_uring cmd and just wait for it to complete
>> to implement the existing synchronous ioctl.
>
> I'd have to look into it, but that sounds like it could be an
> interesting future refactor.
>
> Mark
--
Pavel Begunkov
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 11:26 ` [PATCH] btrfs: add io_uring interface for encoded reads Christoph Hellwig
2024-08-12 14:46 ` Mark Harmstone
@ 2024-08-12 16:10 ` Pavel Begunkov
2024-08-12 16:58 ` David Sterba
1 sibling, 1 reply; 8+ messages in thread
From: Pavel Begunkov @ 2024-08-12 16:10 UTC (permalink / raw)
To: Christoph Hellwig, Mark Harmstone; +Cc: linux-btrfs, Jens Axboe, io-uring
On 8/12/24 12:26, Christoph Hellwig wrote:
> On Fri, Aug 09, 2024 at 06:35:27PM +0100, Mark Harmstone wrote:
Mark, please CC io_uring for next versions, I've only found out
about the patch because Christoph added us.
>> Adds an io_uring interface for asynchronous encoded reads, using the
>> same interface as for the ioctl. To use this you would use an SQE opcode
>> of IORING_OP_URING_CMD, the cmd_op would be BTRFS_IOC_ENCODED_READ, and
>> addr would point to the userspace address of the
>> btrfs_ioctl_encoded_io_args struct. As with the ioctl, you need to have
>> CAP_SYS_ADMIN for this to work.
>
> What is the point if this doesn't actually do anything but returning
> -EIOCBQUEUED?
>
> Note that that the internals of the btrfs encoded read is built
> around kiocbs anyway, so you might as well turn things upside down,
> implement a real async io_uring cmd and just wait for it to complete
> to implement the existing synchronous ioctl.
>
>>
>> Signed-off-by: Mark Harmstone <[email protected]>
>> ---
...
>> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
>> index 0493272a7668..8f5cc7d1429c 100644
>> --- a/fs/btrfs/ioctl.c
>> +++ b/fs/btrfs/ioctl.c
...
>> +static void btrfs_uring_encoded_read_compat_cb(struct io_uring_cmd *cmd,
>> + unsigned int issue_flags)
>> +{
>> + int ret;
>> +
>> + ret = btrfs_ioctl_encoded_read(cmd->file, (void __user *)cmd->sqe->addr,
>> + true);
>> +
>> + io_uring_cmd_done(cmd, ret, 0, issue_flags);
>> +}
>> +
>> +static int btrfs_uring_encoded_read(struct io_uring_cmd *cmd,
>> + unsigned int issue_flags)
>> +{
>> + if (issue_flags & IO_URING_F_COMPAT)
Instead of two different callbacks we can add a helper
# include/linux/io_uring/cmd.h
static inline bool io_uring_cmd_is_compat(struct io_uring_cmd *cmd)
{
#ifdef COMPAT
struct io_kiocb *req = cmd_to_io_kiocb(ioucmd);
return req->ctx->compat;
#else
return false;
#endif
}
But then we pass the flag in btrfs_ioctl_encoded_read() and use to
interpret struct btrfs_ioctl_encoded_io_args, but next just call
import_iovec(), which derives compat differently. Since io_uring worker
threads are now forks of the original thread, ctx->compat vs
in_compat_syscall() are only marginally different, e.g. when we pass a
ring to another process with a different compat'ness, but I don't think
that something we care about much. Let's just make it consistent.
And the last point, I'm surprised there are two versions of
btrfs_ioctl_encoded_io_args. Maybe, it's a good moment to fix it if
we're creating a new interface.
E.g. by adding a new structure defined right with u64 and such, use it
in io_uring, and cast to it in the ioctl code when it's x64 (with
a good set of BUILD_BUG_ON sprinkled) and convert structures otherwise?
>> + io_uring_cmd_complete_in_task(cmd, btrfs_uring_encoded_read_compat_cb);
>> + else
>> + io_uring_cmd_complete_in_task(cmd, btrfs_uring_encoded_read_cb);
As mentioned, the callback will be executed by the submitter task.
You mentioned offloading to a thread/iowq, that would look like:
btrfs_uring_encoded_read() {
if (issue_flags & IO_URING_F_NONBLOCK)
return -EAGAIN;
// it's a worker thread, block is allowed
}
It's a bad pattern though for anything requiring good performance.
At minimum it should try to execute with a nowait flag set first
nowait = issue_flags & IO_URING_F_NONBLOCK;
btrfs_ioctl_encoded_read(..., nowait);
If needs to block it would return -EAGAIN, so that the core
io_uring would spin up a worker thread for it. Even better
if it does it asynchronously as Christoph mentioned.
>> +
>> + return -EIOCBQUEUED;
>> +}
>> +
>> +int btrfs_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
>> +{
>> + switch (cmd->cmd_op) {
>> + case BTRFS_IOC_ENCODED_READ:
>> +#if defined(CONFIG_64BIT) && defined(CONFIG_COMPAT)
>> + case BTRFS_IOC_ENCODED_READ_32:
>> +#endif
>> + return btrfs_uring_encoded_read(cmd, issue_flags);
>> + }
>> +
>> + io_uring_cmd_done(cmd, -EINVAL, 0, issue_flags);
>> + return -EIOCBQUEUED;
>> +}
>> +
>> long btrfs_ioctl(struct file *file, unsigned int
--
Pavel Begunkov
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 16:10 ` Pavel Begunkov
@ 2024-08-12 16:58 ` David Sterba
2024-08-12 19:17 ` Pavel Begunkov
0 siblings, 1 reply; 8+ messages in thread
From: David Sterba @ 2024-08-12 16:58 UTC (permalink / raw)
To: Pavel Begunkov
Cc: Christoph Hellwig, Mark Harmstone, linux-btrfs, Jens Axboe,
io-uring
On Mon, Aug 12, 2024 at 05:10:15PM +0100, Pavel Begunkov wrote:
> And the last point, I'm surprised there are two versions of
> btrfs_ioctl_encoded_io_args. Maybe, it's a good moment to fix it if
> we're creating a new interface.
>
> E.g. by adding a new structure defined right with u64 and such, use it
> in io_uring, and cast to it in the ioctl code when it's x64 (with
> a good set of BUILD_BUG_ON sprinkled) and convert structures otherwise?
If you mean the 32bit version of the ioctl struct
(btrfs_ioctl_encoded_io_args_32), I don't think we can fix it. It's been
there from the beginning and it's not a mistake. I don't remember the
details why and only vaguely remember that I'd asked why we need it.
Similar 64/32 struct is in the send ioctl but that was a mistake due to
a pointer being passed in the structure and that needs to be handled due
to different type width.
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 16:58 ` David Sterba
@ 2024-08-12 19:17 ` Pavel Begunkov
2024-08-13 0:49 ` David Sterba
0 siblings, 1 reply; 8+ messages in thread
From: Pavel Begunkov @ 2024-08-12 19:17 UTC (permalink / raw)
To: dsterba
Cc: Christoph Hellwig, Mark Harmstone, linux-btrfs, Jens Axboe,
io-uring
On 8/12/24 17:58, David Sterba wrote:
> On Mon, Aug 12, 2024 at 05:10:15PM +0100, Pavel Begunkov wrote:
>> And the last point, I'm surprised there are two versions of
>> btrfs_ioctl_encoded_io_args. Maybe, it's a good moment to fix it if
>> we're creating a new interface.
>>
>> E.g. by adding a new structure defined right with u64 and such, use it
>> in io_uring, and cast to it in the ioctl code when it's x64 (with
>> a good set of BUILD_BUG_ON sprinkled) and convert structures otherwise?
>
> If you mean the 32bit version of the ioctl struct
> (btrfs_ioctl_encoded_io_args_32), I don't think we can fix it. It's been
Right, I meant btrfs_ioctl_encoded_io_args_32. And to clarify, nothing
can be done for the ioctl(2) part, I only suggested to have a single
structure when it comes to io_uring.
> there from the beginning and it's not a mistake. I don't remember the
> details why and only vaguely remember that I'd asked why we need it.
> Similar 64/32 struct is in the send ioctl but that was a mistake due to
> a pointer being passed in the structure and that needs to be handled due
> to different type width.
Would be interesting to learn why, maybe Omar remembers? Only two
fields are not explicitly sized, both could've been just u64.
The structure iov points to (struct iovec) would've had a compat
flavour, but that doesn't require a separate
btrfs_ioctl_encoded_io_args.
--
Pavel Begunkov
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-12 19:17 ` Pavel Begunkov
@ 2024-08-13 0:49 ` David Sterba
2024-08-13 1:06 ` Pavel Begunkov
0 siblings, 1 reply; 8+ messages in thread
From: David Sterba @ 2024-08-13 0:49 UTC (permalink / raw)
To: Pavel Begunkov
Cc: dsterba, Christoph Hellwig, Mark Harmstone, linux-btrfs,
Jens Axboe, io-uring
On Mon, Aug 12, 2024 at 08:17:43PM +0100, Pavel Begunkov wrote:
> On 8/12/24 17:58, David Sterba wrote:
> > On Mon, Aug 12, 2024 at 05:10:15PM +0100, Pavel Begunkov wrote:
> >> And the last point, I'm surprised there are two versions of
> >> btrfs_ioctl_encoded_io_args. Maybe, it's a good moment to fix it if
> >> we're creating a new interface.
> >>
> >> E.g. by adding a new structure defined right with u64 and such, use it
> >> in io_uring, and cast to it in the ioctl code when it's x64 (with
> >> a good set of BUILD_BUG_ON sprinkled) and convert structures otherwise?
> >
> > If you mean the 32bit version of the ioctl struct
> > (btrfs_ioctl_encoded_io_args_32), I don't think we can fix it. It's been
>
> Right, I meant btrfs_ioctl_encoded_io_args_32. And to clarify, nothing
> can be done for the ioctl(2) part, I only suggested to have a single
> structure when it comes to io_uring.
>
> > there from the beginning and it's not a mistake. I don't remember the
> > details why and only vaguely remember that I'd asked why we need it.
> > Similar 64/32 struct is in the send ioctl but that was a mistake due to
> > a pointer being passed in the structure and that needs to be handled due
> > to different type width.
>
> Would be interesting to learn why, maybe Omar remembers? Only two
> fields are not explicitly sized, both could've been just u64.
> The structure iov points to (struct iovec) would've had a compat
> flavour, but that doesn't require a separate
> btrfs_ioctl_encoded_io_args.
Found it:
"why don't we avoid the send 32bit workaround"
https://lore.kernel.org/linux-btrfs/[email protected]/
"because big-endian"
https://lore.kernel.org/linux-btrfs/20190903171458.GA7452@vader/
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] btrfs: add io_uring interface for encoded reads
2024-08-13 0:49 ` David Sterba
@ 2024-08-13 1:06 ` Pavel Begunkov
0 siblings, 0 replies; 8+ messages in thread
From: Pavel Begunkov @ 2024-08-13 1:06 UTC (permalink / raw)
To: dsterba
Cc: Christoph Hellwig, Mark Harmstone, linux-btrfs, Jens Axboe,
io-uring
On 8/13/24 01:49, David Sterba wrote:
> On Mon, Aug 12, 2024 at 08:17:43PM +0100, Pavel Begunkov wrote:
>> On 8/12/24 17:58, David Sterba wrote:
>>> On Mon, Aug 12, 2024 at 05:10:15PM +0100, Pavel Begunkov wrote:
>>>> And the last point, I'm surprised there are two versions of
>>>> btrfs_ioctl_encoded_io_args. Maybe, it's a good moment to fix it if
>>>> we're creating a new interface.
>>>>
>>>> E.g. by adding a new structure defined right with u64 and such, use it
>>>> in io_uring, and cast to it in the ioctl code when it's x64 (with
>>>> a good set of BUILD_BUG_ON sprinkled) and convert structures otherwise?
>>>
>>> If you mean the 32bit version of the ioctl struct
>>> (btrfs_ioctl_encoded_io_args_32), I don't think we can fix it. It's been
>>
>> Right, I meant btrfs_ioctl_encoded_io_args_32. And to clarify, nothing
>> can be done for the ioctl(2) part, I only suggested to have a single
>> structure when it comes to io_uring.
>>
>>> there from the beginning and it's not a mistake. I don't remember the
>>> details why and only vaguely remember that I'd asked why we need it.
>>> Similar 64/32 struct is in the send ioctl but that was a mistake due to
>>> a pointer being passed in the structure and that needs to be handled due
>>> to different type width.
>>
>> Would be interesting to learn why, maybe Omar remembers? Only two
>> fields are not explicitly sized, both could've been just u64.
>> The structure iov points to (struct iovec) would've had a compat
>> flavour, but that doesn't require a separate
>> btrfs_ioctl_encoded_io_args.
>
> Found it:
>
> "why don't we avoid the send 32bit workaround"
> https://lore.kernel.org/linux-btrfs/[email protected]/
>
> "because big-endian"
> https://lore.kernel.org/linux-btrfs/20190903171458.GA7452@vader/
union {
void __user *buf;
__u64 __buf_alignment;
};
Endianness is indeed a problem here, but I don't see the
purpose of aliasing it with a pointer instead of keeping
just u64, which is a common pattern.
struct btrfs_ioctl_encoded_io_args {
__u64 buf;
...
};
// user
void *buf = ...;
arg.buf = (__u64)(uintptr_t)buf;
// kernel
void __user *p = u64_to_user_ptr(arg.buf);
--
Pavel Begunkov
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2024-08-13 1:06 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <[email protected]>
2024-08-12 11:26 ` [PATCH] btrfs: add io_uring interface for encoded reads Christoph Hellwig
2024-08-12 14:46 ` Mark Harmstone
2024-08-12 15:03 ` Pavel Begunkov
2024-08-12 16:10 ` Pavel Begunkov
2024-08-12 16:58 ` David Sterba
2024-08-12 19:17 ` Pavel Begunkov
2024-08-13 0:49 ` David Sterba
2024-08-13 1:06 ` Pavel Begunkov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox