io_uring: move xattr related opcodes to its own file
[linux-2.6-block.git] / io_uring / xattr.c
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
20 struct io_xattr {
21         struct file                     *file;
22         struct xattr_ctx                ctx;
23         struct filename                 *filename;
24 };
25
26 void 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
37 static 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
45 static 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
82 int io_fgetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
83 {
84         return __io_getxattr_prep(req, sqe);
85 }
86
87 int 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
108 int 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
124 int 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
134 retry:
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
152 static 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
183 int 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
204 int io_fsetxattr_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
205 {
206         return __io_setxattr_prep(req, sqe);
207 }
208
209 static 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
224 int 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
236 int 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
246 retry:
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 }