Skip to content

Commit

Permalink
io_uring: add fsetxattr and setxattr support
Browse files Browse the repository at this point in the history
This adds support to io_uring for the fsetxattr and setxattr API.

Signed-off-by: Stefan Roesch <shr@fb.com>
Acked-by: Christian Brauner <christian.brauner@ubuntu.com>
Link: https://lore.kernel.org/r/20220323154420.3301504-4-shr@fb.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
  • Loading branch information
Stefan Roesch authored and Jens Axboe committed Apr 25, 2022
1 parent c975cad commit e9621e2
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 1 deletion.
165 changes: 165 additions & 0 deletions fs/io_uring.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
#include <linux/io_uring.h>
#include <linux/audit.h>
#include <linux/security.h>
#include <linux/xattr.h>

#define CREATE_TRACE_POINTS
#include <trace/events/io_uring.h>
Expand Down Expand Up @@ -779,6 +780,12 @@ struct io_async_rw {
struct wait_page_queue wpq;
};

struct io_xattr {
struct file *file;
struct xattr_ctx ctx;
struct filename *filename;
};

enum {
REQ_F_FIXED_FILE_BIT = IOSQE_FIXED_FILE_BIT,
REQ_F_IO_DRAIN_BIT = IOSQE_IO_DRAIN_BIT,
Expand Down Expand Up @@ -943,6 +950,7 @@ struct io_kiocb {
struct io_symlink symlink;
struct io_hardlink hardlink;
struct io_msg msg;
struct io_xattr xattr;
};

u8 opcode;
Expand Down Expand Up @@ -1211,6 +1219,10 @@ static const struct io_op_def io_op_defs[] = {
[IORING_OP_MSG_RING] = {
.needs_file = 1,
},
[IORING_OP_FSETXATTR] = {
.needs_file = 1
},
[IORING_OP_SETXATTR] = {},
};

/* requests with any of those set should undergo io_disarm_next() */
Expand Down Expand Up @@ -4190,6 +4202,144 @@ static int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
return 0;
}

static inline void __io_xattr_finish(struct io_kiocb *req)
{
struct io_xattr *ix = &req->xattr;

if (ix->filename)
putname(ix->filename);

kfree(ix->ctx.kname);
kvfree(ix->ctx.kvalue);
}

static void io_xattr_finish(struct io_kiocb *req, int ret)
{
req->flags &= ~REQ_F_NEED_CLEANUP;

__io_xattr_finish(req);
if (ret < 0)
req_set_fail(req);

io_req_complete(req, ret);
}

static int __io_setxattr_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
struct io_xattr *ix = &req->xattr;
const char __user *name;
int ret;

if (unlikely(req->ctx->flags & IORING_SETUP_IOPOLL))
return -EINVAL;
if (unlikely(sqe->ioprio))
return -EINVAL;
if (unlikely(req->flags & REQ_F_FIXED_FILE))
return -EBADF;

ix->filename = NULL;
name = u64_to_user_ptr(READ_ONCE(sqe->addr));
ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2));
ix->ctx.kvalue = NULL;
ix->ctx.size = READ_ONCE(sqe->len);
ix->ctx.flags = READ_ONCE(sqe->xattr_flags);

ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL);
if (!ix->ctx.kname)
return -ENOMEM;

ret = setxattr_copy(name, &ix->ctx);
if (ret) {
kfree(ix->ctx.kname);
return ret;
}

req->flags |= REQ_F_NEED_CLEANUP;
return 0;
}

static int io_setxattr_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
struct io_xattr *ix = &req->xattr;
const char __user *path;
int ret;

ret = __io_setxattr_prep(req, sqe);
if (ret)
return ret;

path = u64_to_user_ptr(READ_ONCE(sqe->addr3));

ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL);
if (IS_ERR(ix->filename)) {
ret = PTR_ERR(ix->filename);
ix->filename = NULL;
}

return ret;
}

static int io_fsetxattr_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
return __io_setxattr_prep(req, sqe);
}

static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags,
struct path *path)
{
struct io_xattr *ix = &req->xattr;
int ret;

ret = mnt_want_write(path->mnt);
if (!ret) {
ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx);
mnt_drop_write(path->mnt);
}

return ret;
}

static int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags)
{
int ret;

if (issue_flags & IO_URING_F_NONBLOCK)
return -EAGAIN;

ret = __io_setxattr(req, issue_flags, &req->file->f_path);
io_xattr_finish(req, ret);

return 0;
}

static int io_setxattr(struct io_kiocb *req, unsigned int issue_flags)
{
struct io_xattr *ix = &req->xattr;
unsigned int lookup_flags = LOOKUP_FOLLOW;
struct path path;
int ret;

if (issue_flags & IO_URING_F_NONBLOCK)
return -EAGAIN;

retry:
ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL);
if (!ret) {
ret = __io_setxattr(req, issue_flags, &path);
path_put(&path);
if (retry_estale(ret, lookup_flags)) {
lookup_flags |= LOOKUP_REVAL;
goto retry;
}
}

io_xattr_finish(req, ret);
return 0;
}

static int io_unlinkat_prep(struct io_kiocb *req,
const struct io_uring_sqe *sqe)
{
Expand Down Expand Up @@ -7151,6 +7301,10 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
return io_linkat_prep(req, sqe);
case IORING_OP_MSG_RING:
return io_msg_ring_prep(req, sqe);
case IORING_OP_FSETXATTR:
return io_fsetxattr_prep(req, sqe);
case IORING_OP_SETXATTR:
return io_setxattr_prep(req, sqe);
}

printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n",
Expand Down Expand Up @@ -7295,6 +7449,10 @@ static void io_clean_op(struct io_kiocb *req)
if (req->statx.filename)
putname(req->statx.filename);
break;
case IORING_OP_SETXATTR:
case IORING_OP_FSETXATTR:
__io_xattr_finish(req);
break;
}
}
if ((req->flags & REQ_F_POLLED) && req->apoll) {
Expand Down Expand Up @@ -7451,6 +7609,12 @@ static int io_issue_sqe(struct io_kiocb *req, unsigned int issue_flags)
case IORING_OP_MSG_RING:
ret = io_msg_ring(req, issue_flags);
break;
case IORING_OP_FSETXATTR:
ret = io_fsetxattr(req, issue_flags);
break;
case IORING_OP_SETXATTR:
ret = io_setxattr(req, issue_flags);
break;
default:
ret = -EINVAL;
break;
Expand Down Expand Up @@ -12012,6 +12176,7 @@ static int __init io_uring_init(void)
BUILD_BUG_SQE_ELEM(42, __u16, personality);
BUILD_BUG_SQE_ELEM(44, __s32, splice_fd_in);
BUILD_BUG_SQE_ELEM(44, __u32, file_index);
BUILD_BUG_SQE_ELEM(48, __u64, addr3);

BUILD_BUG_ON(sizeof(struct io_uring_files_update) !=
sizeof(struct io_uring_rsrc_update));
Expand Down
6 changes: 5 additions & 1 deletion include/uapi/linux/io_uring.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct io_uring_sqe {
__u32 rename_flags;
__u32 unlink_flags;
__u32 hardlink_flags;
__u32 xattr_flags;
};
__u64 user_data; /* data to be passed back at completion time */
/* pack this to avoid bogus arm OABI complaints */
Expand All @@ -60,7 +61,8 @@ struct io_uring_sqe {
__s32 splice_fd_in;
__u32 file_index;
};
__u64 __pad2[2];
__u64 addr3;
__u64 __pad2[1];
};

enum {
Expand Down Expand Up @@ -145,6 +147,8 @@ enum {
IORING_OP_SYMLINKAT,
IORING_OP_LINKAT,
IORING_OP_MSG_RING,
IORING_OP_FSETXATTR,
IORING_OP_SETXATTR,

/* this goes last, obviously */
IORING_OP_LAST,
Expand Down

0 comments on commit e9621e2

Please sign in to comment.