This provides support for async statx(2) through io_uring.
Unified · Split
| @@ -379,9 +379,13 @@ struct io_sr_msg { · 378 unmodified lines | ||
| 379 | 379 | struct io_open { |
| 380 | 380 | struct file *file; |
| 381 | 381 | int dfd; |
| 382 | − umode_t mode; | |
| 382 | + union { | |
| 383 | + umode_t mode; | |
| 384 | + unsigned mask; | |
| 385 | + }; | |
| 383 | 386 | const char __user *fname; |
| 384 | 387 | struct filename *filename; |
| 388 | + struct statx __user *buffer; | |
| 385 | 389 | int flags; |
| 386 | 390 | }; |
| 387 | 391 | |
| @@ -2266,6 +2270,74 @@ err: · 1878 unmodified lines | ||
| 2266 | 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 | 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 | 3499 | case IORING_OP_FILES_UPDATE: |
| 3428 | 3500 | ret = io_files_update_prep(req, sqe); |
| 3429 | 3501 | break; |
| 3502 | + case IORING_OP_STATX: | |
| 3503 | + ret = io_statx_prep(req, sqe); | |
| 3504 | + break; | |
| 3430 | 3505 | default: |
| 3431 | 3506 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", |
| 3432 | 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 | 3689 | ret = io_files_update(req, force_nonblock); |
| 3615 | 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 | 3699 | default: |
| 3617 | 3700 | ret = -EINVAL; |
| 3618 | 3701 | break; |
| @@ -3699,6 +3782,7 @@ static int io_req_needs_file(struct io_kiocb *req, int fd) · 80 unmodified lines | ||
| 3699 | 3782 | case IORING_OP_LINK_TIMEOUT: |
| 3700 | 3783 | return 0; |
| 3701 | 3784 | case IORING_OP_OPENAT: |
| 3785 | + case IORING_OP_STATX: | |
| 3702 | 3786 | return fd != -1; |
| 3703 | 3787 | default: |
| 3704 | 3788 | if (io_req_op_valid(req->opcode)) |
| @@ -35,6 +35,7 @@ struct io_uring_sqe { · 34 unmodified lines | ||
| 35 | 35 | __u32 accept_flags; |
| 36 | 36 | __u32 cancel_flags; |
| 37 | 37 | __u32 open_flags; |
| 38 | + __u32 statx_flags; | |
| 38 | 39 | }; |
| 39 | 40 | __u64 user_data; /* data to be passed back at completion time */ |
| 40 | 41 | union { |
| @@ -81,6 +82,7 @@ enum { · 40 unmodified lines | ||
| 81 | 82 | IORING_OP_OPENAT, |
| 82 | 83 | IORING_OP_CLOSE, |
| 83 | 84 | IORING_OP_FILES_UPDATE, |
| 85 | + IORING_OP_STATX, | |
| 84 | 86 | |
| 85 | 87 | /* this goes last, obviously */ |
| 86 | 88 | IORING_OP_LAST, |