Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v6.1-rc6 258 lines 5.7 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/kernel.h> 3#include <linux/errno.h> 4#include <linux/fs.h> 5#include <linux/file.h> 6#include <linux/mm.h> 7#include <linux/slab.h> 8#include <linux/namei.h> 9#include <linux/io_uring.h> 10#include <linux/xattr.h> 11 12#include <uapi/linux/io_uring.h> 13 14#include "../fs/internal.h" 15 16#include "io_uring.h" 17#include "xattr.h" 18 19struct io_xattr { 20 struct file *file; 21 struct xattr_ctx ctx; 22 struct filename *filename; 23}; 24 25void io_xattr_cleanup(struct io_kiocb *req) 26{ 27 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 28 29 if (ix->filename) 30 putname(ix->filename); 31 32 kfree(ix->ctx.kname); 33 kvfree(ix->ctx.kvalue); 34} 35 36static void io_xattr_finish(struct io_kiocb *req, int ret) 37{ 38 req->flags &= ~REQ_F_NEED_CLEANUP; 39 40 io_xattr_cleanup(req); 41 io_req_set_res(req, ret, 0); 42} 43 44static int __io_getxattr_prep(struct io_kiocb *req, 45 const struct io_uring_sqe *sqe) 46{ 47 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 48 const char __user *name; 49 int ret; 50 51 if (unlikely(req->flags & REQ_F_FIXED_FILE)) 52 return -EBADF; 53 54 ix->filename = NULL; 55 ix->ctx.kvalue = NULL; 56 name = u64_to_user_ptr(READ_ONCE(sqe->addr)); 57 ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 58 ix->ctx.size = READ_ONCE(sqe->len); 59 ix->ctx.flags = READ_ONCE(sqe->xattr_flags); 60 61 if (ix->ctx.flags) 62 return -EINVAL; 63 64 ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL); 65 if (!ix->ctx.kname) 66 return -ENOMEM; 67 68 ret = strncpy_from_user(ix->ctx.kname->name, name, 69 sizeof(ix->ctx.kname->name)); 70 if (!ret || ret == sizeof(ix->ctx.kname->name)) 71 ret = -ERANGE; 72 if (ret < 0) { 73 kfree(ix->ctx.kname); 74 return ret; 75 } 76 77 req->flags |= REQ_F_NEED_CLEANUP; 78 return 0; 79} 80 81int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 82{ 83 return __io_getxattr_prep(req, sqe); 84} 85 86int io_getxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 87{ 88 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 89 const char __user *path; 90 int ret; 91 92 ret = __io_getxattr_prep(req, sqe); 93 if (ret) 94 return ret; 95 96 path = u64_to_user_ptr(READ_ONCE(sqe->addr3)); 97 98 ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL); 99 if (IS_ERR(ix->filename)) { 100 ret = PTR_ERR(ix->filename); 101 ix->filename = NULL; 102 } 103 104 return ret; 105} 106 107int io_fgetxattr(struct io_kiocb *req, unsigned int issue_flags) 108{ 109 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 110 int ret; 111 112 if (issue_flags & IO_URING_F_NONBLOCK) 113 return -EAGAIN; 114 115 ret = do_getxattr(mnt_user_ns(req->file->f_path.mnt), 116 req->file->f_path.dentry, 117 &ix->ctx); 118 119 io_xattr_finish(req, ret); 120 return IOU_OK; 121} 122 123int io_getxattr(struct io_kiocb *req, unsigned int issue_flags) 124{ 125 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 126 unsigned int lookup_flags = LOOKUP_FOLLOW; 127 struct path path; 128 int ret; 129 130 if (issue_flags & IO_URING_F_NONBLOCK) 131 return -EAGAIN; 132 133retry: 134 ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL); 135 if (!ret) { 136 ret = do_getxattr(mnt_user_ns(path.mnt), 137 path.dentry, 138 &ix->ctx); 139 140 path_put(&path); 141 if (retry_estale(ret, lookup_flags)) { 142 lookup_flags |= LOOKUP_REVAL; 143 goto retry; 144 } 145 } 146 147 io_xattr_finish(req, ret); 148 return IOU_OK; 149} 150 151static int __io_setxattr_prep(struct io_kiocb *req, 152 const struct io_uring_sqe *sqe) 153{ 154 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 155 const char __user *name; 156 int ret; 157 158 if (unlikely(req->flags & REQ_F_FIXED_FILE)) 159 return -EBADF; 160 161 ix->filename = NULL; 162 name = u64_to_user_ptr(READ_ONCE(sqe->addr)); 163 ix->ctx.cvalue = u64_to_user_ptr(READ_ONCE(sqe->addr2)); 164 ix->ctx.kvalue = NULL; 165 ix->ctx.size = READ_ONCE(sqe->len); 166 ix->ctx.flags = READ_ONCE(sqe->xattr_flags); 167 168 ix->ctx.kname = kmalloc(sizeof(*ix->ctx.kname), GFP_KERNEL); 169 if (!ix->ctx.kname) 170 return -ENOMEM; 171 172 ret = setxattr_copy(name, &ix->ctx); 173 if (ret) { 174 kfree(ix->ctx.kname); 175 return ret; 176 } 177 178 req->flags |= REQ_F_NEED_CLEANUP; 179 return 0; 180} 181 182int io_setxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 183{ 184 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 185 const char __user *path; 186 int ret; 187 188 ret = __io_setxattr_prep(req, sqe); 189 if (ret) 190 return ret; 191 192 path = u64_to_user_ptr(READ_ONCE(sqe->addr3)); 193 194 ix->filename = getname_flags(path, LOOKUP_FOLLOW, NULL); 195 if (IS_ERR(ix->filename)) { 196 ret = PTR_ERR(ix->filename); 197 ix->filename = NULL; 198 } 199 200 return ret; 201} 202 203int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) 204{ 205 return __io_setxattr_prep(req, sqe); 206} 207 208static int __io_setxattr(struct io_kiocb *req, unsigned int issue_flags, 209 const struct path *path) 210{ 211 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 212 int ret; 213 214 ret = mnt_want_write(path->mnt); 215 if (!ret) { 216 ret = do_setxattr(mnt_user_ns(path->mnt), path->dentry, &ix->ctx); 217 mnt_drop_write(path->mnt); 218 } 219 220 return ret; 221} 222 223int io_fsetxattr(struct io_kiocb *req, unsigned int issue_flags) 224{ 225 int ret; 226 227 if (issue_flags & IO_URING_F_NONBLOCK) 228 return -EAGAIN; 229 230 ret = __io_setxattr(req, issue_flags, &req->file->f_path); 231 io_xattr_finish(req, ret); 232 return IOU_OK; 233} 234 235int io_setxattr(struct io_kiocb *req, unsigned int issue_flags) 236{ 237 struct io_xattr *ix = io_kiocb_to_cmd(req, struct io_xattr); 238 unsigned int lookup_flags = LOOKUP_FOLLOW; 239 struct path path; 240 int ret; 241 242 if (issue_flags & IO_URING_F_NONBLOCK) 243 return -EAGAIN; 244 245retry: 246 ret = filename_lookup(AT_FDCWD, ix->filename, lookup_flags, &path, NULL); 247 if (!ret) { 248 ret = __io_setxattr(req, issue_flags, &path); 249 path_put(&path); 250 if (retry_estale(ret, lookup_flags)) { 251 lookup_flags |= LOOKUP_REVAL; 252 goto retry; 253 } 254 } 255 256 io_xattr_finish(req, ret); 257 return IOU_OK; 258}