* [PATCH RFC] io_uring: support ioctl
@ 2020-11-02 7:44 Hao Xu
2020-11-02 11:07 ` Pavel Begunkov
0 siblings, 1 reply; 3+ messages in thread
From: Hao Xu @ 2020-11-02 7:44 UTC (permalink / raw)
To: Jens Axboe, io-uring; +Cc: Alexander Viro, linux-fsdevel, Joseph Qi
Async ioctl is necessary for some scenarios like nonblocking
single-threaded model
Signed-off-by: Hao Xu <[email protected]>
---
I've written corresponding liburing tests for this feature. Currently
just a simple test for BLKGETSIZE operation. I'll release it later soon
when it gets better.
fs/io_uring.c | 56 +++++++++++++++++++++++++++++++++++++++++++
fs/ioctl.c | 4 ++--
include/linux/fs.h | 3 ++-
include/uapi/linux/io_uring.h | 1 +
4 files changed, 61 insertions(+), 3 deletions(-)
diff --git a/fs/io_uring.c b/fs/io_uring.c
index b42dfa0243bf..c8ab6b6d2d70 100644
--- a/fs/io_uring.c
+++ b/fs/io_uring.c
@@ -539,6 +539,13 @@ struct io_statx {
struct statx __user *buffer;
};
+struct io_ioctl {
+ struct file *file;
+ unsigned int fd;
+ unsigned int cmd;
+ unsigned long arg;
+};
+
struct io_completion {
struct file *file;
struct list_head list;
@@ -665,6 +672,7 @@ struct io_kiocb {
struct io_splice splice;
struct io_provide_buf pbuf;
struct io_statx statx;
+ struct io_ioctl ioctl;
/* use only after cleaning per-op data, see io_clean_op() */
struct io_completion compl;
};
@@ -932,6 +940,10 @@ struct io_op_def {
.hash_reg_file = 1,
.unbound_nonreg_file = 1,
},
+ [IORING_OP_IOCTL] = {
+ .needs_file = 1,
+ .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FILES
+ },
};
enum io_mem_account {
@@ -4819,6 +4831,45 @@ static int io_connect(struct io_kiocb *req, bool force_nonblock,
}
#endif /* CONFIG_NET */
+static int io_ioctl_prep(struct io_kiocb *req,
+ const struct io_uring_sqe *sqe)
+{
+ if (sqe->ioprio || sqe->buf_index || sqe->rw_flags)
+ return -EINVAL;
+ if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
+ return -EINVAL;
+
+ req->ioctl.fd = READ_ONCE(sqe->fd);
+ req->ioctl.cmd = READ_ONCE(sqe->len);
+ req->ioctl.arg = READ_ONCE(sqe->addr);
+ return 0;
+}
+
+static int io_ioctl(struct io_kiocb *req, bool force_nonblock)
+{
+ int ret;
+
+ if (force_nonblock)
+ return -EAGAIN;
+
+ if (!req->file)
+ return -EBADF;
+
+ ret = security_file_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
+ if (ret)
+ goto out;
+
+ ret = do_vfs_ioctl(req->file, req->ioctl.fd, req->ioctl.cmd, req->ioctl.arg);
+ if (ret == -ENOIOCTLCMD)
+ ret = vfs_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
+
+out:
+ if (ret)
+ req_set_fail_links(req);
+ io_req_complete(req, ret);
+ return 0;
+}
+
struct io_poll_table {
struct poll_table_struct pt;
struct io_kiocb *req;
@@ -5742,6 +5793,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_remove_buffers_prep(req, sqe);
case IORING_OP_TEE:
return io_tee_prep(req, sqe);
+ case IORING_OP_IOCTL:
+ return io_ioctl_prep(req, sqe);
}
printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
@@ -5985,6 +6038,9 @@ static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock,
case IORING_OP_TEE:
ret = io_tee(req, force_nonblock);
break;
+ case IORING_OP_IOCTL:
+ ret = io_ioctl(req, force_nonblock);
+ break;
default:
ret = -EINVAL;
break;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 4e6cc0a7d69c..4ff2eb0d8ee0 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -664,8 +664,8 @@ static int ioctl_file_dedupe_range(struct file *file,
* When you add any new common ioctls to the switches above and below,
* please ensure they have compatible arguments in compat mode.
*/
-static int do_vfs_ioctl(struct file *filp, unsigned int fd,
- unsigned int cmd, unsigned long arg)
+int do_vfs_ioctl(struct file *filp, unsigned int fd,
+ unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
struct inode *inode = file_inode(filp);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 0bd126418bb6..ad62aa6f6136 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1732,7 +1732,8 @@ int vfs_mkobj(struct dentry *, umode_t,
int vfs_utimes(const struct path *path, struct timespec64 *times);
extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-
+extern int do_vfs_ioctl(struct file *filp, unsigned int fd,
+ unsigned int cmd, unsigned long arg);
#ifdef CONFIG_COMPAT
extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
unsigned long arg);
diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
index 98d8e06dea22..4919b4e94c12 100644
--- a/include/uapi/linux/io_uring.h
+++ b/include/uapi/linux/io_uring.h
@@ -132,6 +132,7 @@ enum {
IORING_OP_PROVIDE_BUFFERS,
IORING_OP_REMOVE_BUFFERS,
IORING_OP_TEE,
+ IORING_OP_IOCTL,
/* this goes last, obviously */
IORING_OP_LAST,
--
1.8.3.1
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH RFC] io_uring: support ioctl
2020-11-02 7:44 [PATCH RFC] io_uring: support ioctl Hao Xu
@ 2020-11-02 11:07 ` Pavel Begunkov
2020-11-03 3:02 ` Hao Xu
0 siblings, 1 reply; 3+ messages in thread
From: Pavel Begunkov @ 2020-11-02 11:07 UTC (permalink / raw)
To: Hao Xu, Jens Axboe, io-uring; +Cc: Alexander Viro, linux-fsdevel, Joseph Qi
On 02/11/2020 07:44, Hao Xu wrote:
> Async ioctl is necessary for some scenarios like nonblocking
> single-threaded model
Once I fell for it myself, see Jann explained why that's a bad idea.
https://lore.kernel.org/io-uring/CAG48ez0N_b+kjbddhHe+BUvSnOSvpm1vdfQ9cv+cgTLuCMXqug@mail.gmail.com/
>
> Signed-off-by: Hao Xu <[email protected]>
> ---
> I've written corresponding liburing tests for this feature. Currently
> just a simple test for BLKGETSIZE operation. I'll release it later soon
> when it gets better.
>
> fs/io_uring.c | 56 +++++++++++++++++++++++++++++++++++++++++++
> fs/ioctl.c | 4 ++--
> include/linux/fs.h | 3 ++-
> include/uapi/linux/io_uring.h | 1 +
> 4 files changed, 61 insertions(+), 3 deletions(-)
>
> diff --git a/fs/io_uring.c b/fs/io_uring.c
> index b42dfa0243bf..c8ab6b6d2d70 100644
> --- a/fs/io_uring.c
> +++ b/fs/io_uring.c
> @@ -539,6 +539,13 @@ struct io_statx {
> struct statx __user *buffer;
> };
>
> +struct io_ioctl {
> + struct file *file;
> + unsigned int fd;
> + unsigned int cmd;
> + unsigned long arg;
> +};
> +
> struct io_completion {
> struct file *file;
> struct list_head list;
> @@ -665,6 +672,7 @@ struct io_kiocb {
> struct io_splice splice;
> struct io_provide_buf pbuf;
> struct io_statx statx;
> + struct io_ioctl ioctl;
> /* use only after cleaning per-op data, see io_clean_op() */
> struct io_completion compl;
> };
> @@ -932,6 +940,10 @@ struct io_op_def {
> .hash_reg_file = 1,
> .unbound_nonreg_file = 1,
> },
> + [IORING_OP_IOCTL] = {
> + .needs_file = 1,
> + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FILES
> + },
> };
>
> enum io_mem_account {
> @@ -4819,6 +4831,45 @@ static int io_connect(struct io_kiocb *req, bool force_nonblock,
> }
> #endif /* CONFIG_NET */
>
> +static int io_ioctl_prep(struct io_kiocb *req,
> + const struct io_uring_sqe *sqe)
> +{
> + if (sqe->ioprio || sqe->buf_index || sqe->rw_flags)
> + return -EINVAL;
> + if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
> + return -EINVAL;
> +
> + req->ioctl.fd = READ_ONCE(sqe->fd);
> + req->ioctl.cmd = READ_ONCE(sqe->len);
> + req->ioctl.arg = READ_ONCE(sqe->addr);
> + return 0;
> +}
> +
> +static int io_ioctl(struct io_kiocb *req, bool force_nonblock)
> +{
> + int ret;
> +
> + if (force_nonblock)
> + return -EAGAIN;
> +
> + if (!req->file)
> + return -EBADF;
> +
> + ret = security_file_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
> + if (ret)
> + goto out;
> +
> + ret = do_vfs_ioctl(req->file, req->ioctl.fd, req->ioctl.cmd, req->ioctl.arg);
> + if (ret == -ENOIOCTLCMD)
> + ret = vfs_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
> +
> +out:
> + if (ret)
> + req_set_fail_links(req);
> + io_req_complete(req, ret);
> + return 0;
> +}
> +
> struct io_poll_table {
> struct poll_table_struct pt;
> struct io_kiocb *req;
> @@ -5742,6 +5793,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
> return io_remove_buffers_prep(req, sqe);
> case IORING_OP_TEE:
> return io_tee_prep(req, sqe);
> + case IORING_OP_IOCTL:
> + return io_ioctl_prep(req, sqe);
> }
>
> printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
> @@ -5985,6 +6038,9 @@ static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock,
> case IORING_OP_TEE:
> ret = io_tee(req, force_nonblock);
> break;
> + case IORING_OP_IOCTL:
> + ret = io_ioctl(req, force_nonblock);
> + break;
> default:
> ret = -EINVAL;
> break;
> diff --git a/fs/ioctl.c b/fs/ioctl.c
> index 4e6cc0a7d69c..4ff2eb0d8ee0 100644
> --- a/fs/ioctl.c
> +++ b/fs/ioctl.c
> @@ -664,8 +664,8 @@ static int ioctl_file_dedupe_range(struct file *file,
> * When you add any new common ioctls to the switches above and below,
> * please ensure they have compatible arguments in compat mode.
> */
> -static int do_vfs_ioctl(struct file *filp, unsigned int fd,
> - unsigned int cmd, unsigned long arg)
> +int do_vfs_ioctl(struct file *filp, unsigned int fd,
> + unsigned int cmd, unsigned long arg)
> {
> void __user *argp = (void __user *)arg;
> struct inode *inode = file_inode(filp);
> diff --git a/include/linux/fs.h b/include/linux/fs.h
> index 0bd126418bb6..ad62aa6f6136 100644
> --- a/include/linux/fs.h
> +++ b/include/linux/fs.h
> @@ -1732,7 +1732,8 @@ int vfs_mkobj(struct dentry *, umode_t,
> int vfs_utimes(const struct path *path, struct timespec64 *times);
>
> extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
> -
> +extern int do_vfs_ioctl(struct file *filp, unsigned int fd,
> + unsigned int cmd, unsigned long arg);
> #ifdef CONFIG_COMPAT
> extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
> unsigned long arg);
> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
> index 98d8e06dea22..4919b4e94c12 100644
> --- a/include/uapi/linux/io_uring.h
> +++ b/include/uapi/linux/io_uring.h
> @@ -132,6 +132,7 @@ enum {
> IORING_OP_PROVIDE_BUFFERS,
> IORING_OP_REMOVE_BUFFERS,
> IORING_OP_TEE,
> + IORING_OP_IOCTL,
>
> /* this goes last, obviously */
> IORING_OP_LAST,
>
--
Pavel Begunkov
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH RFC] io_uring: support ioctl
2020-11-02 11:07 ` Pavel Begunkov
@ 2020-11-03 3:02 ` Hao Xu
0 siblings, 0 replies; 3+ messages in thread
From: Hao Xu @ 2020-11-03 3:02 UTC (permalink / raw)
To: Pavel Begunkov, Jens Axboe, io-uring
Cc: Alexander Viro, linux-fsdevel, Joseph Qi
在 2020/11/2 下午7:07, Pavel Begunkov 写道:
> On 02/11/2020 07:44, Hao Xu wrote:
>> Async ioctl is necessary for some scenarios like nonblocking
>> single-threaded model
>
> Once I fell for it myself, see Jann explained why that's a bad idea.
Thanks, Pavel. The information is helpful and make sense to me.
It seems I have to rethink it. Btw, your version is more robust.
> https://lore.kernel.org/io-uring/CAG48ez0N_b+kjbddhHe+BUvSnOSvpm1vdfQ9cv+cgTLuCMXqug@mail.gmail.com/
>
>>
>> Signed-off-by: Hao Xu <[email protected]>
>> ---
>> I've written corresponding liburing tests for this feature. Currently
>> just a simple test for BLKGETSIZE operation. I'll release it later soon
>> when it gets better.
>>
>> fs/io_uring.c | 56 +++++++++++++++++++++++++++++++++++++++++++
>> fs/ioctl.c | 4 ++--
>> include/linux/fs.h | 3 ++-
>> include/uapi/linux/io_uring.h | 1 +
>> 4 files changed, 61 insertions(+), 3 deletions(-)
>>
>> diff --git a/fs/io_uring.c b/fs/io_uring.c
>> index b42dfa0243bf..c8ab6b6d2d70 100644
>> --- a/fs/io_uring.c
>> +++ b/fs/io_uring.c
>> @@ -539,6 +539,13 @@ struct io_statx {
>> struct statx __user *buffer;
>> };
>>
>> +struct io_ioctl {
>> + struct file *file;
>> + unsigned int fd;
>> + unsigned int cmd;
>> + unsigned long arg;
>> +};
>> +
>> struct io_completion {
>> struct file *file;
>> struct list_head list;
>> @@ -665,6 +672,7 @@ struct io_kiocb {
>> struct io_splice splice;
>> struct io_provide_buf pbuf;
>> struct io_statx statx;
>> + struct io_ioctl ioctl;
>> /* use only after cleaning per-op data, see io_clean_op() */
>> struct io_completion compl;
>> };
>> @@ -932,6 +940,10 @@ struct io_op_def {
>> .hash_reg_file = 1,
>> .unbound_nonreg_file = 1,
>> },
>> + [IORING_OP_IOCTL] = {
>> + .needs_file = 1,
>> + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FILES
>> + },
>> };
>>
>> enum io_mem_account {
>> @@ -4819,6 +4831,45 @@ static int io_connect(struct io_kiocb *req, bool force_nonblock,
>> }
>> #endif /* CONFIG_NET */
>>
>> +static int io_ioctl_prep(struct io_kiocb *req,
>> + const struct io_uring_sqe *sqe)
>> +{
>> + if (sqe->ioprio || sqe->buf_index || sqe->rw_flags)
>> + return -EINVAL;
>> + if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
>> + return -EINVAL;
>> +
>> + req->ioctl.fd = READ_ONCE(sqe->fd);
>> + req->ioctl.cmd = READ_ONCE(sqe->len);
>> + req->ioctl.arg = READ_ONCE(sqe->addr);
>> + return 0;
>> +}
>> +
>> +static int io_ioctl(struct io_kiocb *req, bool force_nonblock)
>> +{
>> + int ret;
>> +
>> + if (force_nonblock)
>> + return -EAGAIN;
>> +
>> + if (!req->file)
>> + return -EBADF;
>> +
>> + ret = security_file_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
>> + if (ret)
>> + goto out;
>> +
>> + ret = do_vfs_ioctl(req->file, req->ioctl.fd, req->ioctl.cmd, req->ioctl.arg);
>> + if (ret == -ENOIOCTLCMD)
>> + ret = vfs_ioctl(req->file, req->ioctl.cmd, req->ioctl.arg);
>> +
>> +out:
>> + if (ret)
>> + req_set_fail_links(req);
>> + io_req_complete(req, ret);
>> + return 0;
>> +}
>> +
>> struct io_poll_table {
>> struct poll_table_struct pt;
>> struct io_kiocb *req;
>> @@ -5742,6 +5793,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
>> return io_remove_buffers_prep(req, sqe);
>> case IORING_OP_TEE:
>> return io_tee_prep(req, sqe);
>> + case IORING_OP_IOCTL:
>> + return io_ioctl_prep(req, sqe);
>> }
>>
>> printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
>> @@ -5985,6 +6038,9 @@ static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock,
>> case IORING_OP_TEE:
>> ret = io_tee(req, force_nonblock);
>> break;
>> + case IORING_OP_IOCTL:
>> + ret = io_ioctl(req, force_nonblock);
>> + break;
>> default:
>> ret = -EINVAL;
>> break;
>> diff --git a/fs/ioctl.c b/fs/ioctl.c
>> index 4e6cc0a7d69c..4ff2eb0d8ee0 100644
>> --- a/fs/ioctl.c
>> +++ b/fs/ioctl.c
>> @@ -664,8 +664,8 @@ static int ioctl_file_dedupe_range(struct file *file,
>> * When you add any new common ioctls to the switches above and below,
>> * please ensure they have compatible arguments in compat mode.
>> */
>> -static int do_vfs_ioctl(struct file *filp, unsigned int fd,
>> - unsigned int cmd, unsigned long arg)
>> +int do_vfs_ioctl(struct file *filp, unsigned int fd,
>> + unsigned int cmd, unsigned long arg)
>> {
>> void __user *argp = (void __user *)arg;
>> struct inode *inode = file_inode(filp);
>> diff --git a/include/linux/fs.h b/include/linux/fs.h
>> index 0bd126418bb6..ad62aa6f6136 100644
>> --- a/include/linux/fs.h
>> +++ b/include/linux/fs.h
>> @@ -1732,7 +1732,8 @@ int vfs_mkobj(struct dentry *, umode_t,
>> int vfs_utimes(const struct path *path, struct timespec64 *times);
>>
>> extern long vfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
>> -
>> +extern int do_vfs_ioctl(struct file *filp, unsigned int fd,
>> + unsigned int cmd, unsigned long arg);
>> #ifdef CONFIG_COMPAT
>> extern long compat_ptr_ioctl(struct file *file, unsigned int cmd,
>> unsigned long arg);
>> diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h
>> index 98d8e06dea22..4919b4e94c12 100644
>> --- a/include/uapi/linux/io_uring.h
>> +++ b/include/uapi/linux/io_uring.h
>> @@ -132,6 +132,7 @@ enum {
>> IORING_OP_PROVIDE_BUFFERS,
>> IORING_OP_REMOVE_BUFFERS,
>> IORING_OP_TEE,
>> + IORING_OP_IOCTL,
>>
>> /* this goes last, obviously */
>> IORING_OP_LAST,
>>
>
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2020-11-03 3:03 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-11-02 7:44 [PATCH RFC] io_uring: support ioctl Hao Xu
2020-11-02 11:07 ` Pavel Begunkov
2020-11-03 3:02 ` Hao Xu
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox