mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07: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 install_fd_flags;
|
||||
__u32 nop_flags;
|
||||
__u32 pipe_flags;
|
||||
};
|
||||
__u64 user_data; /* data to be passed back at completion time */
|
||||
/* pack this to avoid bogus arm OABI complaints */
|
||||
@@ -283,6 +284,7 @@ enum io_uring_op {
|
||||
IORING_OP_EPOLL_WAIT,
|
||||
IORING_OP_READV_FIXED,
|
||||
IORING_OP_WRITEV_FIXED,
|
||||
IORING_OP_PIPE,
|
||||
|
||||
/* this goes last, obviously */
|
||||
IORING_OP_LAST,
|
||||
|
||||
@@ -569,6 +569,10 @@ const struct io_issue_def io_issue_defs[] = {
|
||||
.prep = io_prep_writev_fixed,
|
||||
.issue = io_write,
|
||||
},
|
||||
[IORING_OP_PIPE] = {
|
||||
.prep = io_pipe_prep,
|
||||
.issue = io_pipe,
|
||||
},
|
||||
};
|
||||
|
||||
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,
|
||||
.fail = io_rw_fail,
|
||||
},
|
||||
[IORING_OP_PIPE] = {
|
||||
.name = "PIPE",
|
||||
},
|
||||
};
|
||||
|
||||
const char *io_uring_get_opcode(u8 opcode)
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <linux/fdtable.h>
|
||||
#include <linux/fsnotify.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/pipe_fs_i.h>
|
||||
#include <linux/watch_queue.h>
|
||||
#include <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);
|
||||
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(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(struct io_kiocb *req, unsigned int issue_flags);
|
||||
|
||||
Reference in New Issue
Block a user