mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-05 08:18:02 -04:00
io_uring: add support for IORING_OP_PIPE
This works just like pipe2(2), except it also supports fixed file descriptors. Used in a similar fashion as for other fd instantiating opcodes (like accept, socket, open, etc), where sqe->file_slot is set appropriately if two direct descriptors are desired rather than a set of normal file descriptors. sqe->addr must be set to a pointer to an array of 2 integers, which is where the fixed/normal file descriptors are copied to. sqe->pipe_flags contains flags, same as what is allowed for pipe2(2). Future expansion of per-op private flags can go in sqe->ioprio, like we do for other opcodes that take both a "syscall" flag set and an io_uring opcode specific flag set. Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
@@ -73,6 +73,7 @@ struct io_uring_sqe {
|
|||||||
__u32 futex_flags;
|
__u32 futex_flags;
|
||||||
__u32 install_fd_flags;
|
__u32 install_fd_flags;
|
||||||
__u32 nop_flags;
|
__u32 nop_flags;
|
||||||
|
__u32 pipe_flags;
|
||||||
};
|
};
|
||||||
__u64 user_data; /* data to be passed back at completion time */
|
__u64 user_data; /* data to be passed back at completion time */
|
||||||
/* pack this to avoid bogus arm OABI complaints */
|
/* pack this to avoid bogus arm OABI complaints */
|
||||||
@@ -283,6 +284,7 @@ enum io_uring_op {
|
|||||||
IORING_OP_EPOLL_WAIT,
|
IORING_OP_EPOLL_WAIT,
|
||||||
IORING_OP_READV_FIXED,
|
IORING_OP_READV_FIXED,
|
||||||
IORING_OP_WRITEV_FIXED,
|
IORING_OP_WRITEV_FIXED,
|
||||||
|
IORING_OP_PIPE,
|
||||||
|
|
||||||
/* this goes last, obviously */
|
/* this goes last, obviously */
|
||||||
IORING_OP_LAST,
|
IORING_OP_LAST,
|
||||||
|
|||||||
@@ -569,6 +569,10 @@ const struct io_issue_def io_issue_defs[] = {
|
|||||||
.prep = io_prep_writev_fixed,
|
.prep = io_prep_writev_fixed,
|
||||||
.issue = io_write,
|
.issue = io_write,
|
||||||
},
|
},
|
||||||
|
[IORING_OP_PIPE] = {
|
||||||
|
.prep = io_pipe_prep,
|
||||||
|
.issue = io_pipe,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct io_cold_def io_cold_defs[] = {
|
const struct io_cold_def io_cold_defs[] = {
|
||||||
@@ -815,6 +819,9 @@ const struct io_cold_def io_cold_defs[] = {
|
|||||||
.cleanup = io_readv_writev_cleanup,
|
.cleanup = io_readv_writev_cleanup,
|
||||||
.fail = io_rw_fail,
|
.fail = io_rw_fail,
|
||||||
},
|
},
|
||||||
|
[IORING_OP_PIPE] = {
|
||||||
|
.name = "PIPE",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *io_uring_get_opcode(u8 opcode)
|
const char *io_uring_get_opcode(u8 opcode)
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
#include <linux/fdtable.h>
|
#include <linux/fdtable.h>
|
||||||
#include <linux/fsnotify.h>
|
#include <linux/fsnotify.h>
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
|
#include <linux/pipe_fs_i.h>
|
||||||
|
#include <linux/watch_queue.h>
|
||||||
#include <linux/io_uring.h>
|
#include <linux/io_uring.h>
|
||||||
|
|
||||||
#include <uapi/linux/io_uring.h>
|
#include <uapi/linux/io_uring.h>
|
||||||
@@ -302,3 +304,134 @@ int io_install_fixed_fd(struct io_kiocb *req, unsigned int issue_flags)
|
|||||||
io_req_set_res(req, ret, 0);
|
io_req_set_res(req, ret, 0);
|
||||||
return IOU_OK;
|
return IOU_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct io_pipe {
|
||||||
|
struct file *file;
|
||||||
|
int __user *fds;
|
||||||
|
int flags;
|
||||||
|
int file_slot;
|
||||||
|
unsigned long nofile;
|
||||||
|
};
|
||||||
|
|
||||||
|
int io_pipe_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
||||||
|
{
|
||||||
|
struct io_pipe *p = io_kiocb_to_cmd(req, struct io_pipe);
|
||||||
|
|
||||||
|
if (sqe->fd || sqe->off || sqe->addr3)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
p->fds = u64_to_user_ptr(READ_ONCE(sqe->addr));
|
||||||
|
p->flags = READ_ONCE(sqe->pipe_flags);
|
||||||
|
if (p->flags & ~(O_CLOEXEC | O_NONBLOCK | O_DIRECT | O_NOTIFICATION_PIPE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
p->file_slot = READ_ONCE(sqe->file_index);
|
||||||
|
p->nofile = rlimit(RLIMIT_NOFILE);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int io_pipe_fixed(struct io_kiocb *req, struct file **files,
|
||||||
|
unsigned int issue_flags)
|
||||||
|
{
|
||||||
|
struct io_pipe *p = io_kiocb_to_cmd(req, struct io_pipe);
|
||||||
|
struct io_ring_ctx *ctx = req->ctx;
|
||||||
|
int ret, fds[2] = { -1, -1 };
|
||||||
|
int slot = p->file_slot;
|
||||||
|
|
||||||
|
if (p->flags & O_CLOEXEC)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
io_ring_submit_lock(ctx, issue_flags);
|
||||||
|
|
||||||
|
ret = __io_fixed_fd_install(ctx, files[0], slot);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
fds[0] = ret;
|
||||||
|
files[0] = NULL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If a specific slot is given, next one will be used for
|
||||||
|
* the write side.
|
||||||
|
*/
|
||||||
|
if (slot != IORING_FILE_INDEX_ALLOC)
|
||||||
|
slot++;
|
||||||
|
|
||||||
|
ret = __io_fixed_fd_install(ctx, files[1], slot);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
fds[1] = ret;
|
||||||
|
files[1] = NULL;
|
||||||
|
|
||||||
|
io_ring_submit_unlock(ctx, issue_flags);
|
||||||
|
|
||||||
|
if (!copy_to_user(p->fds, fds, sizeof(fds)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = -EFAULT;
|
||||||
|
io_ring_submit_lock(ctx, issue_flags);
|
||||||
|
err:
|
||||||
|
if (fds[0] != -1)
|
||||||
|
io_fixed_fd_remove(ctx, fds[0]);
|
||||||
|
if (fds[1] != -1)
|
||||||
|
io_fixed_fd_remove(ctx, fds[1]);
|
||||||
|
io_ring_submit_unlock(ctx, issue_flags);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int io_pipe_fd(struct io_kiocb *req, struct file **files)
|
||||||
|
{
|
||||||
|
struct io_pipe *p = io_kiocb_to_cmd(req, struct io_pipe);
|
||||||
|
int ret, fds[2] = { -1, -1 };
|
||||||
|
|
||||||
|
ret = __get_unused_fd_flags(p->flags, p->nofile);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
fds[0] = ret;
|
||||||
|
|
||||||
|
ret = __get_unused_fd_flags(p->flags, p->nofile);
|
||||||
|
if (ret < 0)
|
||||||
|
goto err;
|
||||||
|
fds[1] = ret;
|
||||||
|
|
||||||
|
if (!copy_to_user(p->fds, fds, sizeof(fds))) {
|
||||||
|
fd_install(fds[0], files[0]);
|
||||||
|
fd_install(fds[1], files[1]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ret = -EFAULT;
|
||||||
|
err:
|
||||||
|
if (fds[0] != -1)
|
||||||
|
put_unused_fd(fds[0]);
|
||||||
|
if (fds[1] != -1)
|
||||||
|
put_unused_fd(fds[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int io_pipe(struct io_kiocb *req, unsigned int issue_flags)
|
||||||
|
{
|
||||||
|
struct io_pipe *p = io_kiocb_to_cmd(req, struct io_pipe);
|
||||||
|
struct file *files[2];
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = create_pipe_files(files, p->flags);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
files[0]->f_mode |= FMODE_NOWAIT;
|
||||||
|
files[1]->f_mode |= FMODE_NOWAIT;
|
||||||
|
|
||||||
|
if (!!p->file_slot)
|
||||||
|
ret = io_pipe_fixed(req, files, issue_flags);
|
||||||
|
else
|
||||||
|
ret = io_pipe_fd(req, files);
|
||||||
|
|
||||||
|
io_req_set_res(req, ret, 0);
|
||||||
|
if (!ret)
|
||||||
|
return IOU_OK;
|
||||||
|
|
||||||
|
req_set_fail(req);
|
||||||
|
if (files[0])
|
||||||
|
fput(files[0]);
|
||||||
|
if (files[1])
|
||||||
|
fput(files[1]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,5 +13,8 @@ int io_openat2(struct io_kiocb *req, unsigned int issue_flags);
|
|||||||
int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||||
int io_close(struct io_kiocb *req, unsigned int issue_flags);
|
int io_close(struct io_kiocb *req, unsigned int issue_flags);
|
||||||
|
|
||||||
|
int io_pipe_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||||
|
int io_pipe(struct io_kiocb *req, unsigned int issue_flags);
|
||||||
|
|
||||||
int io_install_fixed_fd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
int io_install_fixed_fd_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe);
|
||||||
int io_install_fixed_fd(struct io_kiocb *req, unsigned int issue_flags);
|
int io_install_fixed_fd(struct io_kiocb *req, unsigned int issue_flags);
|
||||||
|
|||||||
Reference in New Issue
Block a user