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