IORING_OP_UNLINKAT behaves like unlinkat(2) and takes the same flags and arguments.
Unified · Split
| @@ -555,6 +555,13 @@ struct io_rename { · 554 unmodified lines | ||
| 555 | 555 | int flags; |
| 556 | 556 | }; |
| 557 | 557 | |
| 558 | +struct io_unlink { | |
| 559 | + struct file *file; | |
| 560 | + int dfd; | |
| 561 | + int flags; | |
| 562 | + struct filename *filename; | |
| 563 | +}; | |
| 564 | + | |
| 558 | 565 | struct io_completion { |
| 559 | 566 | struct file *file; |
| 560 | 567 | struct list_head list; |
| @@ -683,6 +690,7 @@ struct io_kiocb { · 122 unmodified lines | ||
| 683 | 690 | struct io_statx statx; |
| 684 | 691 | struct io_shutdown shutdown; |
| 685 | 692 | struct io_rename rename; |
| 693 | + struct io_unlink unlink; | |
| 686 | 694 | /* use only after cleaning per-op data, see io_clean_op() */ |
| 687 | 695 | struct io_completion compl; |
| 688 | 696 | }; |
| @@ -957,6 +965,10 @@ static const struct io_op_def io_op_defs[] = { · 268 unmodified lines | ||
| 957 | 965 | .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FILES | |
| 958 | 966 | IO_WQ_WORK_FS | IO_WQ_WORK_BLKCG, |
| 959 | 967 | }, |
| 968 | + [IORING_OP_UNLINKAT] = { | |
| 969 | + .work_flags = IO_WQ_WORK_MM | IO_WQ_WORK_FILES | | |
| 970 | + IO_WQ_WORK_FS | IO_WQ_WORK_BLKCG, | |
| 971 | + }, | |
| 960 | 972 | }; |
| 961 | 973 | |
| 962 | 974 | enum io_mem_account { |
| @@ -3706,6 +3718,50 @@ static int io_renameat(struct io_kiocb *req, bool force_nonblock) · 2743 unmodified lines | ||
| 3706 | 3718 | return 0; |
| 3707 | 3719 | } |
| 3708 | 3720 | |
| 3721 | +static int io_unlinkat_prep(struct io_kiocb *req, | |
| 3722 | + const struct io_uring_sqe *sqe) | |
| 3723 | +{ | |
| 3724 | + struct io_unlink *un = &req->unlink; | |
| 3725 | + const char __user *fname; | |
| 3726 | + | |
| 3727 | + if (unlikely(req->flags & REQ_F_FIXED_FILE)) | |
| 3728 | + return -EBADF; | |
| 3729 | + | |
| 3730 | + un->dfd = READ_ONCE(sqe->fd); | |
| 3731 | + | |
| 3732 | + un->flags = READ_ONCE(sqe->unlink_flags); | |
| 3733 | + if (un->flags & ~AT_REMOVEDIR) | |
| 3734 | + return -EINVAL; | |
| 3735 | + | |
| 3736 | + fname = u64_to_user_ptr(READ_ONCE(sqe->addr)); | |
| 3737 | + un->filename = getname(fname); | |
| 3738 | + if (IS_ERR(un->filename)) | |
| 3739 | + return PTR_ERR(un->filename); | |
| 3740 | + | |
| 3741 | + req->flags |= REQ_F_NEED_CLEANUP; | |
| 3742 | + return 0; | |
| 3743 | +} | |
| 3744 | + | |
| 3745 | +static int io_unlinkat(struct io_kiocb *req, bool force_nonblock) | |
| 3746 | +{ | |
| 3747 | + struct io_unlink *un = &req->unlink; | |
| 3748 | + int ret; | |
| 3749 | + | |
| 3750 | + if (force_nonblock) | |
| 3751 | + return -EAGAIN; | |
| 3752 | + | |
| 3753 | + if (un->flags & AT_REMOVEDIR) | |
| 3754 | + ret = do_rmdir(un->dfd, un->filename); | |
| 3755 | + else | |
| 3756 | + ret = do_unlinkat(un->dfd, un->filename); | |
| 3757 | + | |
| 3758 | + req->flags &= ~REQ_F_NEED_CLEANUP; | |
| 3759 | + if (ret < 0) | |
| 3760 | + req_set_fail_links(req); | |
| 3761 | + io_req_complete(req, ret); | |
| 3762 | + return 0; | |
| 3763 | +} | |
| 3764 | + | |
| 3709 | 3765 | static int io_shutdown_prep(struct io_kiocb *req, |
| 3710 | 3766 | const struct io_uring_sqe *sqe) |
| 3711 | 3767 | { |
| @@ -5932,6 +5988,8 @@ static int io_req_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) · 2220 unmodified lines | ||
| 5932 | 5988 | return io_shutdown_prep(req, sqe); |
| 5933 | 5989 | case IORING_OP_RENAMEAT: |
| 5934 | 5990 | return io_renameat_prep(req, sqe); |
| 5991 | + case IORING_OP_UNLINKAT: | |
| 5992 | + return io_unlinkat_prep(req, sqe); | |
| 5935 | 5993 | } |
| 5936 | 5994 | |
| 5937 | 5995 | printk_once(KERN_WARNING "io_uring: unhandled opcode %d\n", |
| @@ -6073,6 +6131,9 @@ static void __io_clean_op(struct io_kiocb *req) · 135 unmodified lines | ||
| 6073 | 6131 | putname(req->rename.oldpath); |
| 6074 | 6132 | putname(req->rename.newpath); |
| 6075 | 6133 | break; |
| 6134 | + case IORING_OP_UNLINKAT: | |
| 6135 | + putname(req->unlink.filename); | |
| 6136 | + break; | |
| 6076 | 6137 | } |
| 6077 | 6138 | req->flags &= ~REQ_F_NEED_CLEANUP; |
| 6078 | 6139 | } |
| @@ -6185,6 +6246,9 @@ static int io_issue_sqe(struct io_kiocb *req, bool force_nonblock, · 106 unmodified lines | ||
| 6185 | 6246 | case IORING_OP_RENAMEAT: |
| 6186 | 6247 | ret = io_renameat(req, force_nonblock); |
| 6187 | 6248 | break; |
| 6249 | + case IORING_OP_UNLINKAT: | |
| 6250 | + ret = io_unlinkat(req, force_nonblock); | |
| 6251 | + break; | |
| 6188 | 6252 | default: |
| 6189 | 6253 | ret = -EINVAL; |
| 6190 | 6254 | break; |
| @@ -43,6 +43,7 @@ struct io_uring_sqe { · 42 unmodified lines | ||
| 43 | 43 | __u32 fadvise_advice; |
| 44 | 44 | __u32 splice_flags; |
| 45 | 45 | __u32 rename_flags; |
| 46 | + __u32 unlink_flags; | |
| 46 | 47 | }; |
| 47 | 48 | __u64 user_data; /* data to be passed back at completion time */ |
| 48 | 49 | union { |
| @@ -135,6 +136,7 @@ enum { · 86 unmodified lines | ||
| 135 | 136 | IORING_OP_TEE, |
| 136 | 137 | IORING_OP_SHUTDOWN, |
| 137 | 138 | IORING_OP_RENAMEAT, |
| 139 | + IORING_OP_UNLINKAT, | |
| 138 | 140 | |
| 139 | 141 | /* this goes last, obviously */ |
| 140 | 142 | IORING_OP_LAST, |