Line data Source code
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 :
11 : #include <uapi/linux/io_uring.h>
12 :
13 : #include "../fs/internal.h"
14 :
15 : #include "io_uring.h"
16 : #include "fs.h"
17 :
18 : struct io_rename {
19 : struct file *file;
20 : int old_dfd;
21 : int new_dfd;
22 : struct filename *oldpath;
23 : struct filename *newpath;
24 : int flags;
25 : };
26 :
27 : struct io_unlink {
28 : struct file *file;
29 : int dfd;
30 : int flags;
31 : struct filename *filename;
32 : };
33 :
34 : struct io_mkdir {
35 : struct file *file;
36 : int dfd;
37 : umode_t mode;
38 : struct filename *filename;
39 : };
40 :
41 : struct io_link {
42 : struct file *file;
43 : int old_dfd;
44 : int new_dfd;
45 : struct filename *oldpath;
46 : struct filename *newpath;
47 : int flags;
48 : };
49 :
50 0 : int io_renameat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
51 : {
52 0 : struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
53 : const char __user *oldf, *newf;
54 :
55 0 : if (sqe->buf_index || sqe->splice_fd_in)
56 : return -EINVAL;
57 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
58 : return -EBADF;
59 :
60 0 : ren->old_dfd = READ_ONCE(sqe->fd);
61 0 : oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
62 0 : newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
63 0 : ren->new_dfd = READ_ONCE(sqe->len);
64 0 : ren->flags = READ_ONCE(sqe->rename_flags);
65 :
66 0 : ren->oldpath = getname(oldf);
67 0 : if (IS_ERR(ren->oldpath))
68 0 : return PTR_ERR(ren->oldpath);
69 :
70 0 : ren->newpath = getname(newf);
71 0 : if (IS_ERR(ren->newpath)) {
72 0 : putname(ren->oldpath);
73 0 : return PTR_ERR(ren->newpath);
74 : }
75 :
76 0 : req->flags |= REQ_F_NEED_CLEANUP;
77 0 : req->flags |= REQ_F_FORCE_ASYNC;
78 0 : return 0;
79 : }
80 :
81 0 : int io_renameat(struct io_kiocb *req, unsigned int issue_flags)
82 : {
83 0 : struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
84 : int ret;
85 :
86 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
87 :
88 0 : ret = do_renameat2(ren->old_dfd, ren->oldpath, ren->new_dfd,
89 0 : ren->newpath, ren->flags);
90 :
91 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
92 0 : io_req_set_res(req, ret, 0);
93 0 : return IOU_OK;
94 : }
95 :
96 0 : void io_renameat_cleanup(struct io_kiocb *req)
97 : {
98 0 : struct io_rename *ren = io_kiocb_to_cmd(req, struct io_rename);
99 :
100 0 : putname(ren->oldpath);
101 0 : putname(ren->newpath);
102 0 : }
103 :
104 0 : int io_unlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
105 : {
106 0 : struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
107 : const char __user *fname;
108 :
109 0 : if (sqe->off || sqe->len || sqe->buf_index || sqe->splice_fd_in)
110 : return -EINVAL;
111 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
112 : return -EBADF;
113 :
114 0 : un->dfd = READ_ONCE(sqe->fd);
115 :
116 0 : un->flags = READ_ONCE(sqe->unlink_flags);
117 0 : if (un->flags & ~AT_REMOVEDIR)
118 : return -EINVAL;
119 :
120 0 : fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
121 0 : un->filename = getname(fname);
122 0 : if (IS_ERR(un->filename))
123 0 : return PTR_ERR(un->filename);
124 :
125 0 : req->flags |= REQ_F_NEED_CLEANUP;
126 0 : req->flags |= REQ_F_FORCE_ASYNC;
127 0 : return 0;
128 : }
129 :
130 0 : int io_unlinkat(struct io_kiocb *req, unsigned int issue_flags)
131 : {
132 0 : struct io_unlink *un = io_kiocb_to_cmd(req, struct io_unlink);
133 : int ret;
134 :
135 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
136 :
137 0 : if (un->flags & AT_REMOVEDIR)
138 0 : ret = do_rmdir(un->dfd, un->filename);
139 : else
140 0 : ret = do_unlinkat(un->dfd, un->filename);
141 :
142 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
143 0 : io_req_set_res(req, ret, 0);
144 0 : return IOU_OK;
145 : }
146 :
147 0 : void io_unlinkat_cleanup(struct io_kiocb *req)
148 : {
149 0 : struct io_unlink *ul = io_kiocb_to_cmd(req, struct io_unlink);
150 :
151 0 : putname(ul->filename);
152 0 : }
153 :
154 0 : int io_mkdirat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
155 : {
156 0 : struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
157 : const char __user *fname;
158 :
159 0 : if (sqe->off || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
160 : return -EINVAL;
161 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
162 : return -EBADF;
163 :
164 0 : mkd->dfd = READ_ONCE(sqe->fd);
165 0 : mkd->mode = READ_ONCE(sqe->len);
166 :
167 0 : fname = u64_to_user_ptr(READ_ONCE(sqe->addr));
168 0 : mkd->filename = getname(fname);
169 0 : if (IS_ERR(mkd->filename))
170 0 : return PTR_ERR(mkd->filename);
171 :
172 0 : req->flags |= REQ_F_NEED_CLEANUP;
173 0 : req->flags |= REQ_F_FORCE_ASYNC;
174 0 : return 0;
175 : }
176 :
177 0 : int io_mkdirat(struct io_kiocb *req, unsigned int issue_flags)
178 : {
179 0 : struct io_mkdir *mkd = io_kiocb_to_cmd(req, struct io_mkdir);
180 : int ret;
181 :
182 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
183 :
184 0 : ret = do_mkdirat(mkd->dfd, mkd->filename, mkd->mode);
185 :
186 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
187 0 : io_req_set_res(req, ret, 0);
188 0 : return IOU_OK;
189 : }
190 :
191 0 : void io_mkdirat_cleanup(struct io_kiocb *req)
192 : {
193 0 : struct io_mkdir *md = io_kiocb_to_cmd(req, struct io_mkdir);
194 :
195 0 : putname(md->filename);
196 0 : }
197 :
198 0 : int io_symlinkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
199 : {
200 0 : struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
201 : const char __user *oldpath, *newpath;
202 :
203 0 : if (sqe->len || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
204 : return -EINVAL;
205 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
206 : return -EBADF;
207 :
208 0 : sl->new_dfd = READ_ONCE(sqe->fd);
209 0 : oldpath = u64_to_user_ptr(READ_ONCE(sqe->addr));
210 0 : newpath = u64_to_user_ptr(READ_ONCE(sqe->addr2));
211 :
212 0 : sl->oldpath = getname(oldpath);
213 0 : if (IS_ERR(sl->oldpath))
214 0 : return PTR_ERR(sl->oldpath);
215 :
216 0 : sl->newpath = getname(newpath);
217 0 : if (IS_ERR(sl->newpath)) {
218 0 : putname(sl->oldpath);
219 0 : return PTR_ERR(sl->newpath);
220 : }
221 :
222 0 : req->flags |= REQ_F_NEED_CLEANUP;
223 0 : req->flags |= REQ_F_FORCE_ASYNC;
224 0 : return 0;
225 : }
226 :
227 0 : int io_symlinkat(struct io_kiocb *req, unsigned int issue_flags)
228 : {
229 0 : struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
230 : int ret;
231 :
232 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
233 :
234 0 : ret = do_symlinkat(sl->oldpath, sl->new_dfd, sl->newpath);
235 :
236 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
237 0 : io_req_set_res(req, ret, 0);
238 0 : return IOU_OK;
239 : }
240 :
241 0 : int io_linkat_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
242 : {
243 0 : struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
244 : const char __user *oldf, *newf;
245 :
246 0 : if (sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)
247 : return -EINVAL;
248 0 : if (unlikely(req->flags & REQ_F_FIXED_FILE))
249 : return -EBADF;
250 :
251 0 : lnk->old_dfd = READ_ONCE(sqe->fd);
252 0 : lnk->new_dfd = READ_ONCE(sqe->len);
253 0 : oldf = u64_to_user_ptr(READ_ONCE(sqe->addr));
254 0 : newf = u64_to_user_ptr(READ_ONCE(sqe->addr2));
255 0 : lnk->flags = READ_ONCE(sqe->hardlink_flags);
256 :
257 0 : lnk->oldpath = getname(oldf);
258 0 : if (IS_ERR(lnk->oldpath))
259 0 : return PTR_ERR(lnk->oldpath);
260 :
261 0 : lnk->newpath = getname(newf);
262 0 : if (IS_ERR(lnk->newpath)) {
263 0 : putname(lnk->oldpath);
264 0 : return PTR_ERR(lnk->newpath);
265 : }
266 :
267 0 : req->flags |= REQ_F_NEED_CLEANUP;
268 0 : req->flags |= REQ_F_FORCE_ASYNC;
269 0 : return 0;
270 : }
271 :
272 0 : int io_linkat(struct io_kiocb *req, unsigned int issue_flags)
273 : {
274 0 : struct io_link *lnk = io_kiocb_to_cmd(req, struct io_link);
275 : int ret;
276 :
277 0 : WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK);
278 :
279 0 : ret = do_linkat(lnk->old_dfd, lnk->oldpath, lnk->new_dfd,
280 : lnk->newpath, lnk->flags);
281 :
282 0 : req->flags &= ~REQ_F_NEED_CLEANUP;
283 0 : io_req_set_res(req, ret, 0);
284 0 : return IOU_OK;
285 : }
286 :
287 0 : void io_link_cleanup(struct io_kiocb *req)
288 : {
289 0 : struct io_link *sl = io_kiocb_to_cmd(req, struct io_link);
290 :
291 0 : putname(sl->oldpath);
292 0 : putname(sl->newpath);
293 0 : }
|