This provides support for async statx(2) through io_uring.
Unified · Split
| @@ -379,9 +379,13 @@ struct io_sr_msg { · 378 unmodified lines | |||
| 379 | struct io_open { | 379 | struct io_open { |
| 380 | struct file *file; | 380 | struct file *file; |
| 381 | int dfd; | 381 | int dfd; |
| 382 | umode_t mode; | 382 | union { |
| 383 | umode_t mode; | ||
| 384 | unsigned mask; | ||
| 385 | }; | ||
| 383 | const char __user *fname; | 386 | const char __user *fname; |
| 384 | struct filename *filename; | 387 | struct filename *filename; |
| 388 | struct statx __user *buffer; | ||
| 385 | int flags; | 389 | int flags; |
| 386 | }; | 390 | }; |
| 387 | 391 | ||
| @@ -2266,6 +2270,74 @@ err: · 1878 unmodified lines | |||
| 2266 | return 0; | 2270 | return 0; |
| 2267 | } | 2271 | } |
| 2268 | 2272 | ||
| 2273 | static int io_statx_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) | ||
| 2274 | { | ||
| 2275 | unsigned lookup_flags; | ||
| 2276 | int ret; | ||
| 2277 | |||
| 2278 | if (sqe->ioprio || sqe->buf_index) | ||
| 2279 | return -EINVAL; | ||
| 2280 | |||
| 2281 | req->open.dfd = READ_ONCE(sqe->fd); | ||
| 2282 | req->open.mask = READ_ONCE(sqe->len); | ||
| 2283 | req->open.fname = u64_to_user_ptr(READ_ONCE(sqe->addr)); | ||
| 2284 | req->open.buffer = u64_to_user_ptr(READ_ONCE(sqe->addr2)); | ||
| 2285 | req->open.flags = READ_ONCE(sqe->statx_flags); | ||
| 2286 | |||
| 2287 | if (vfs_stat_set_lookup_flags(&lookup_flags, req->open.flags)) | ||
| 2288 | return -EINVAL; | ||
| 2289 | |||
| 2290 | req->open.filename = getname_flags(req->open.fname, lookup_flags, NULL); | ||
| 2291 | if (IS_ERR(req->open.filename)) { | ||
| 2292 | ret = PTR_ERR(req->open.filename); | ||
| 2293 | req->open.filename = NULL; | ||
| 2294 | return ret; | ||
| 2295 | } | ||
| 2296 | |||
| 2297 | return 0; | ||
| 2298 | } | ||
| 2299 | |||
| 2300 | static int io_statx(struct io_kiocb *req, struct io_kiocb **nxt, | ||
| 2301 | bool force_nonblock) | ||
| 2302 | { | ||
| 2303 | struct io_open *ctx = &req->open; | ||
| 2304 | unsigned lookup_flags; | ||
| 2305 | struct path path; | ||
| 2306 | struct kstat stat; | ||
| 2307 | int ret; | ||
| 2308 | |||
| 2309 | if (force_nonblock) | ||
| 2310 | return -EAGAIN; | ||
| 2311 | |||
| 2312 | if (vfs_stat_set_lookup_flags(&lookup_flags, ctx->flags)) | ||
| 2313 | return -EINVAL; | ||
| 2314 | |||
| 2315 | retry: | ||
| 2316 | /* filename_lookup() drops it, keep a reference */ | ||
| 2317 | ctx->filename->refcnt++; | ||
| 2318 | |||
| 2319 | ret = filename_lookup(ctx->dfd, ctx->filename, lookup_flags, &path, | ||
| 2320 | NULL); | ||
| 2321 | if (ret) | ||
| 2322 | goto err; | ||
| 2323 | |||
| 2324 | ret = vfs_getattr(&path, &stat, ctx->mask, ctx->flags); | ||
| 2325 | path_put(&path); | ||
| 2326 | if (retry_estale(ret, lookup_flags)) { | ||
| 2327 | lookup_flags |= LOOKUP_REVAL; | ||
| 2328 | goto retry; | ||
| 2329 | } | ||
| 2330 | if (!ret) | ||
| 2331 | ret = cp_statx(&stat, ctx->buffer); | ||
| 2332 | err: | ||
| 2333 | putname(ctx->filename); | ||
| 2334 | if (ret < 0) | ||
| 2335 | req_set_fail_links(req); | ||
| 2336 | io_cqring_add_event(req, ret); | ||
| 2337 | io_put_req_find_next(req, nxt); | ||
| 2338 | return 0; | ||
| 2339 | } | ||
| 2340 | |||
| 2269 | static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) | 2341 | static int io_close_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) |
| 2270 | { | 2342 | { |
| 2271 | /* | 2343 | /* |
| @@ -3427,6 +3499,9 @@ static int io_req_defer_prep(struct io_kiocb *req, · 1155 unmodified lines | |||
| 3427 | case IORING_OP_FILES_UPDATE: | 3499 | case IORING_OP_FILES_UPDATE: |
| 3428 | ret = io_files_update_prep(req, sqe); | 3500 | ret = io_files_update_prep(req, sqe); |
| 3429 | break; | 3501 | break; |
| 3502 | case IORING_OP_STATX: | ||
| 3503 | ret = io_statx_prep(req, sqe); | ||
| 3504 | break; | ||
| 3430 | default: | 3505 | default: |
| 3431 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", | 3506 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", |
| 3432 | req->opcode); | 3507 | req->opcode); |
| @@ -3613,6 +3688,14 @@ static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe, · 180 unmodified lines | |||
| 3613 | } | 3688 | } |
| 3614 | ret = io_files_update(req, force_nonblock); | 3689 | ret = io_files_update(req, force_nonblock); |
| 3615 | break; | 3690 | break; |
| 3691 | case IORING_OP_STATX: | ||
| 3692 | if (sqe) { | ||
| 3693 | ret = io_statx_prep(req, sqe); | ||
| 3694 | if (ret) | ||
| 3695 | break; | ||
| 3696 | } | ||
| 3697 | ret = io_statx(req, nxt, force_nonblock); | ||
| 3698 | break; | ||
| 3616 | default: | 3699 | default: |
| 3617 | ret = -EINVAL; | 3700 | ret = -EINVAL; |
| 3618 | break; | 3701 | break; |
| @@ -3699,6 +3782,7 @@ static int io_req_needs_file(struct io_kiocb *req, int fd) · 80 unmodified lines | |||
| 3699 | case IORING_OP_LINK_TIMEOUT: | 3782 | case IORING_OP_LINK_TIMEOUT: |
| 3700 | return 0; | 3783 | return 0; |
| 3701 | case IORING_OP_OPENAT: | 3784 | case IORING_OP_OPENAT: |
| 3785 | case IORING_OP_STATX: | ||
| 3702 | return fd != -1; | 3786 | return fd != -1; |
| 3703 | default: | 3787 | default: |
| 3704 | if (io_req_op_valid(req->opcode)) | 3788 | if (io_req_op_valid(req->opcode)) |
| @@ -35,6 +35,7 @@ struct io_uring_sqe { · 34 unmodified lines | |||
| 35 | __u32 accept_flags; | 35 | __u32 accept_flags; |
| 36 | __u32 cancel_flags; | 36 | __u32 cancel_flags; |
| 37 | __u32 open_flags; | 37 | __u32 open_flags; |
| 38 | __u32 statx_flags; | ||
| 38 | }; | 39 | }; |
| 39 | __u64 user_data; /* data to be passed back at completion time */ | 40 | __u64 user_data; /* data to be passed back at completion time */ |
| 40 | union { | 41 | union { |
| @@ -81,6 +82,7 @@ enum { · 40 unmodified lines | |||
| 81 | IORING_OP_OPENAT, | 82 | IORING_OP_OPENAT, |
| 82 | IORING_OP_CLOSE, | 83 | IORING_OP_CLOSE, |
| 83 | IORING_OP_FILES_UPDATE, | 84 | IORING_OP_FILES_UPDATE, |
| 85 | IORING_OP_STATX, | ||
| 84 | 86 | ||
| 85 | /* this goes last, obviously */ | 87 | /* this goes last, obviously */ |
| 86 | IORING_OP_LAST, | 88 | IORING_OP_LAST, |