Overlay notification control onto IORING_OP_RSRC_UPDATE (former IORING_OP_FILES_UPDATE). It allows to flush a range of zc notifications from slots with indexes [sqe->off, sqe->off+sqe->len). If sqe->arg is not zero, it also copies sqe->arg as a new tag for all flushed notifications. Note, it doesn't flush a notification of a slot if there was no requests attached to it (since last flush or registration). Signed-off-by: Pavel Begunkov <asml.silence@xxxxxxxxx> --- fs/io_uring.c | 47 +++++++++++++++++++++++++++++++++++ include/uapi/linux/io_uring.h | 1 + 2 files changed, 48 insertions(+) diff --git a/fs/io_uring.c b/fs/io_uring.c index e9fc7e076c7f..a88c9c73ed1d 100644 --- a/fs/io_uring.c +++ b/fs/io_uring.c @@ -1284,6 +1284,7 @@ static const struct io_op_def io_op_defs[] = { [IORING_OP_RSRC_UPDATE] = { .audit_skip = 1, .iopoll = 1, + .ioprio = 1, }, [IORING_OP_STATX] = { .audit_skip = 1, @@ -2953,6 +2954,16 @@ static void io_notif_slot_flush(struct io_notif_slot *slot) io_notif_complete(notif); } +static inline void io_notif_slot_flush_submit(struct io_notif_slot *slot, + unsigned int issue_flags) +{ + if (!(issue_flags & IO_URING_F_UNLOCKED)) { + slot->notif->task = current; + io_get_task_refs(1); + } + io_notif_slot_flush(slot); +} + static __cold int io_notif_unregister(struct io_ring_ctx *ctx) __must_hold(&ctx->uring_lock) { @@ -8286,6 +8297,40 @@ static int io_rsrc_update_prep(struct io_kiocb *req, return 0; } +static int io_notif_update(struct io_kiocb *req, unsigned int issue_flags) +{ + struct io_ring_ctx *ctx = req->ctx; + unsigned len = req->rsrc_update.nr_args; + unsigned idx_end, idx = req->rsrc_update.offset; + int ret = 0; + + io_ring_submit_lock(ctx, issue_flags); + if (unlikely(check_add_overflow(idx, len, &idx_end))) { + ret = -EOVERFLOW; + goto out; + } + if (unlikely(idx_end > ctx->nr_notif_slots)) { + ret = -EINVAL; + goto out; + } + + for (; idx < idx_end; idx++) { + struct io_notif_slot *slot = &ctx->notif_slots[idx]; + + if (!slot->notif) + continue; + if (req->rsrc_update.arg) + slot->tag = req->rsrc_update.arg; + io_notif_slot_flush_submit(slot, issue_flags); + } +out: + io_ring_submit_unlock(ctx, issue_flags); + if (ret < 0) + req_set_fail(req); + __io_req_complete(req, issue_flags, ret, 0); + return 0; +} + static int io_files_update(struct io_kiocb *req, unsigned int issue_flags) { struct io_ring_ctx *ctx = req->ctx; @@ -8315,6 +8360,8 @@ static int io_rsrc_update(struct io_kiocb *req, unsigned int issue_flags) switch (req->rsrc_update.type) { case IORING_RSRC_UPDATE_FILES: return io_files_update(req, issue_flags); + case IORING_RSRC_UPDATE_NOTIF: + return io_notif_update(req, issue_flags); } return -EINVAL; } diff --git a/include/uapi/linux/io_uring.h b/include/uapi/linux/io_uring.h index 5f574558b96c..19b9d7a2da29 100644 --- a/include/uapi/linux/io_uring.h +++ b/include/uapi/linux/io_uring.h @@ -266,6 +266,7 @@ enum io_uring_op { */ enum { IORING_RSRC_UPDATE_FILES, + IORING_RSRC_UPDATE_NOTIF, }; /* -- 2.36.1