mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 01:32:21 +02:00
io_uring-7.2-20260625
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmo9GAwQHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgpoQ5D/9yn5dVqZLzqshu/sXJ3uw8usm+u+wvinc1 l6Lp2Q5sfAtmN+nGIZJvwRGqpglw4RRKxiZVHm2yGJ79g3HJIAIgcmlBLtI7HwZ0 foaKhaYB2hvEr6E/hpc0gL3OcRuc3cYjtWu9TsA3OOU4yf9vt9JehHoqlll0SOju a+0d7EJJ0HaEdi52qhMPhgiWaLfWfD5UGKkVZZTn8JfLyli8Mvn18zcmdSJ82WVp 1CSaquc02meIKUEGruB2T0pQe1Nnk20trP3rosGzc54h501W81hB2vZIVRi7lq5S m4jgDM+xp/H31JXoelz2VXXXWEg+wxuB2u8WsVuD2yjJc5HFD/S5NKWOJ4oKbae/ A/5xujtkOLPrVeEZmoP/pvAZbEbjpRxw7hwhKWQeed5ir82TgV0MRoiBMsYBpKW8 xfLAn/aJiU0O6F0xcftOsMibWLR40raIk1+OdoWm+JWFELzcF03bQ/875zqbFu9h /7EFhYWgMW8mvn+/gH5IiN04YxdWu13RsWHi93didxxeCRN8YGgJgH8ysyIhE5O6 Tbcdu0ye0NY4O0JuWVrxowHOno5MewUO7SWUbBOEOsrn8Xc4Bl3oFRbIYuwph5Jz rhABOf5Rkyt7ypOV8PWDwroTj3IAUq02HivsesRMxbcEEM/cgvIcse19qAIo+dGW LkIJCI+H3Q== =cmtx -----END PGP SIGNATURE----- Merge tag 'io_uring-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux Pull io_uring fixes from Jens Axboe: - Fix a file reference leak in the nop opcode when used with IOSQE_FIXED_FILE - Preserve the SQ array entries when resizing the ring via the register path - Preserve the partial result for an iopoll request rather than overwriting it - Don't audit log IORING_OP_RECV_ZC - Bound io_pin_pages() by the page array byte size in the memmap path - Follow-up cleanup to the task_work mpscq conversion, getting rid of the now-unnecessary tw_pending tracking for the !DEFER_TASKRUN path - Switch a system_unbound_wq user over to system_dfl_wq * tag 'io_uring-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: io_uring/memmap: bound io_pin_pages() by page array byte size io_uring: Use system_dfl_wq instead of system_unbound_wq io_uring/register: preserve SQ array entries on resize io_uring, audit: don't log IORING_OP_RECV_ZC io_uring: get rid of tw_pending for !DEFER task work io_uring/rw: preserve partial result for iopoll io_uring/nop: fix file reference leak with IOSQE_FIXED_FILE
This commit is contained in:
commit
c58ddac1aa
|
|
@ -149,8 +149,6 @@ struct io_uring_task {
|
|||
|
||||
struct { /* task_work */
|
||||
struct mpscq task_list;
|
||||
/* BIT(0) guards adding tw only once */
|
||||
unsigned long tw_pending;
|
||||
struct callback_head task_work;
|
||||
} ____cacheline_aligned_in_smp;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ struct page **io_pin_pages(unsigned long uaddr, unsigned long len, int *npages)
|
|||
nr_pages = end - start;
|
||||
if (WARN_ON_ONCE(!nr_pages))
|
||||
return ERR_PTR(-EINVAL);
|
||||
if (WARN_ON_ONCE(nr_pages > INT_MAX))
|
||||
if (nr_pages > INT_MAX / sizeof(struct page *))
|
||||
return ERR_PTR(-EOVERFLOW);
|
||||
|
||||
pages = kvmalloc_objs(struct page *, nr_pages, GFP_KERNEL_ACCOUNT);
|
||||
|
|
|
|||
|
|
@ -122,4 +122,13 @@ static inline struct llist_node *mpscq_pop(struct mpscq *q,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the most recent mpscq_pop() that returned a node also
|
||||
* emptied the queue. Consumer must be serialized.
|
||||
*/
|
||||
static inline bool mpscq_pop_emptied(struct mpscq *q, struct llist_node *head)
|
||||
{
|
||||
return head == &q->stub;
|
||||
}
|
||||
|
||||
#endif /* IOU_MPSCQ_H */
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ int io_nop_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
|
|||
nop->fd = READ_ONCE(sqe->fd);
|
||||
else
|
||||
nop->fd = -1;
|
||||
if (nop->flags & IORING_NOP_FIXED_FILE)
|
||||
req->flags |= REQ_F_FIXED_FILE;
|
||||
if (nop->flags & IORING_NOP_FIXED_BUFFER)
|
||||
req->buf_index = READ_ONCE(sqe->buf_index);
|
||||
if (nop->flags & IORING_NOP_CQE32) {
|
||||
|
|
@ -59,12 +61,10 @@ int io_nop(struct io_kiocb *req, unsigned int issue_flags)
|
|||
int ret = nop->result;
|
||||
|
||||
if (nop->flags & IORING_NOP_FILE) {
|
||||
if (nop->flags & IORING_NOP_FIXED_FILE) {
|
||||
if (req->flags & REQ_F_FIXED_FILE)
|
||||
req->file = io_file_get_fixed(req, nop->fd, issue_flags);
|
||||
req->flags |= REQ_F_FIXED_FILE;
|
||||
} else {
|
||||
else
|
||||
req->file = io_file_get_normal(req, nop->fd);
|
||||
}
|
||||
if (!req->file) {
|
||||
ret = -EBADF;
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -520,6 +520,7 @@ const struct io_issue_def io_issue_defs[] = {
|
|||
#endif
|
||||
},
|
||||
[IORING_OP_RECV_ZC] = {
|
||||
.audit_skip = 1,
|
||||
.needs_file = 1,
|
||||
.unbound_nonreg_file = 1,
|
||||
.pollin = 1,
|
||||
|
|
|
|||
|
|
@ -503,6 +503,7 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
|||
unsigned i, tail, old_head;
|
||||
struct io_uring_params *p = &config.p;
|
||||
struct io_rings_layout *rl = &config.layout;
|
||||
u32 *o_sq_array, *n_sq_array = NULL;
|
||||
int ret;
|
||||
|
||||
memset(&config, 0, sizeof(config));
|
||||
|
|
@ -589,6 +590,9 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
|||
ctx->rings = NULL;
|
||||
o.sq_sqes = ctx->sq_sqes;
|
||||
ctx->sq_sqes = NULL;
|
||||
o_sq_array = ctx->sq_array;
|
||||
if (!(ctx->flags & IORING_SETUP_NO_SQARRAY))
|
||||
n_sq_array = (u32 *)((char *)n.rings + rl->sq_array_offset);
|
||||
|
||||
/*
|
||||
* Now copy SQ and CQ entries, if any. If either of the destination
|
||||
|
|
@ -599,20 +603,27 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
|||
if (tail - old_head > p->sq_entries)
|
||||
goto overflow;
|
||||
for (i = old_head; i < tail; i++) {
|
||||
unsigned index, dst_mask, src_mask;
|
||||
unsigned int dst, src;
|
||||
size_t sq_size;
|
||||
|
||||
index = i;
|
||||
sq_size = sizeof(struct io_uring_sqe);
|
||||
src_mask = ctx->sq_entries - 1;
|
||||
dst_mask = p->sq_entries - 1;
|
||||
if (ctx->flags & IORING_SETUP_SQE128) {
|
||||
index <<= 1;
|
||||
sq_size <<= 1;
|
||||
src_mask = (ctx->sq_entries << 1) - 1;
|
||||
dst_mask = (p->sq_entries << 1) - 1;
|
||||
dst = i & (p->sq_entries - 1);
|
||||
src = i & (ctx->sq_entries - 1);
|
||||
if (n_sq_array) {
|
||||
src = READ_ONCE(o_sq_array[src]);
|
||||
if (unlikely(src >= ctx->sq_entries)) {
|
||||
WRITE_ONCE(n_sq_array[dst], UINT_MAX);
|
||||
continue;
|
||||
}
|
||||
WRITE_ONCE(n_sq_array[dst], dst);
|
||||
}
|
||||
memcpy(&n.sq_sqes[index & dst_mask], &o.sq_sqes[index & src_mask], sq_size);
|
||||
|
||||
sq_size = sizeof(struct io_uring_sqe);
|
||||
if (ctx->flags & IORING_SETUP_SQE128) {
|
||||
dst <<= 1;
|
||||
src <<= 1;
|
||||
sq_size <<= 1;
|
||||
}
|
||||
memcpy(&n.sq_sqes[dst], &o.sq_sqes[src], sq_size);
|
||||
}
|
||||
WRITE_ONCE(n.rings->sq.head, old_head);
|
||||
WRITE_ONCE(n.rings->sq.tail, tail);
|
||||
|
|
@ -655,8 +666,8 @@ static int io_register_resize_rings(struct io_ring_ctx *ctx, void __user *arg)
|
|||
WRITE_ONCE(n.rings->cq_overflow, READ_ONCE(o.rings->cq_overflow));
|
||||
|
||||
/* all done, store old pointers and assign new ones */
|
||||
if (!(ctx->flags & IORING_SETUP_NO_SQARRAY))
|
||||
ctx->sq_array = (u32 *)((char *)n.rings + rl->sq_array_offset);
|
||||
if (n_sq_array)
|
||||
ctx->sq_array = n_sq_array;
|
||||
|
||||
ctx->sq_entries = p->sq_entries;
|
||||
ctx->cq_entries = p->cq_entries;
|
||||
|
|
|
|||
|
|
@ -601,15 +601,15 @@ static void io_complete_rw_iopoll(struct kiocb *kiocb, long res)
|
|||
{
|
||||
struct io_rw *rw = container_of(kiocb, struct io_rw, kiocb);
|
||||
struct io_kiocb *req = cmd_to_io_kiocb(rw);
|
||||
int final_res = io_fixup_rw_res(req, res);
|
||||
|
||||
if (kiocb->ki_flags & IOCB_WRITE)
|
||||
io_req_end_write(req);
|
||||
if (unlikely(res != req->cqe.res)) {
|
||||
if (res == -EAGAIN && io_rw_should_reissue(req))
|
||||
req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE;
|
||||
else
|
||||
req->cqe.res = res;
|
||||
}
|
||||
|
||||
if (res == -EAGAIN && io_rw_should_reissue(req))
|
||||
req->flags |= REQ_F_REISSUE | REQ_F_BL_NO_RECYCLE;
|
||||
else if (unlikely(final_res != req->cqe.res))
|
||||
req->cqe.res = final_res;
|
||||
|
||||
/* order with io_iopoll_complete() checking ->iopoll_completed */
|
||||
smp_store_release(&req->iopoll_completed, 1);
|
||||
|
|
|
|||
|
|
@ -34,10 +34,6 @@ void io_tctx_fallback_work(struct work_struct *work)
|
|||
fallback_work);
|
||||
unsigned int count = 0;
|
||||
|
||||
/* see tctx_task_work() - a set bit must always have a run coming */
|
||||
clear_bit(0, &tctx->tw_pending);
|
||||
smp_mb__after_atomic();
|
||||
|
||||
/*
|
||||
* Run the entries directly. We're in PF_KTHRED context, hence
|
||||
* io_should_terminate_tw() is true and they will be marked as
|
||||
|
|
@ -55,7 +51,7 @@ static void io_fallback_tw(struct io_uring_task *tctx)
|
|||
* the queued work) stay around until the drain has run.
|
||||
*/
|
||||
get_task_struct(tctx->task);
|
||||
if (!queue_work(system_unbound_wq, &tctx->fallback_work))
|
||||
if (!queue_work(system_dfl_wq, &tctx->fallback_work))
|
||||
put_task_struct(tctx->task);
|
||||
}
|
||||
|
||||
|
|
@ -101,6 +97,13 @@ void tctx_task_work_run(struct io_uring_task *tctx, unsigned int max_entries,
|
|||
io_poll_task_func, io_req_rw_complete,
|
||||
(struct io_tw_req){req}, ts);
|
||||
(*count)++;
|
||||
/*
|
||||
* Break if most recent pop emptied the queue. This helps
|
||||
* bound task_work run, and also protects the regular
|
||||
* task_work addition.
|
||||
*/
|
||||
if (mpscq_pop_emptied(&tctx->task_list, tctx->task_head))
|
||||
break;
|
||||
if (unlikely(need_resched())) {
|
||||
ctx_flush_and_put(ctx, ts);
|
||||
ctx = NULL;
|
||||
|
|
@ -127,8 +130,6 @@ void tctx_task_work(struct callback_head *cb)
|
|||
unsigned int count = 0;
|
||||
|
||||
tctx = container_of(cb, struct io_uring_task, task_work);
|
||||
clear_bit(0, &tctx->tw_pending);
|
||||
smp_mb__after_atomic();
|
||||
tctx_task_work_run(tctx, UINT_MAX, &count);
|
||||
}
|
||||
|
||||
|
|
@ -206,7 +207,7 @@ void io_req_normal_work_add(struct io_kiocb *req)
|
|||
struct io_uring_task *tctx = req->tctx;
|
||||
struct io_ring_ctx *ctx = req->ctx;
|
||||
|
||||
/* task_work already pending, we're done */
|
||||
/* tw run already pending, nothing else to do */
|
||||
if (!mpscq_push(&tctx->task_list, &req->io_task_work.node))
|
||||
return;
|
||||
|
||||
|
|
@ -223,10 +224,6 @@ void io_req_normal_work_add(struct io_kiocb *req)
|
|||
return;
|
||||
}
|
||||
|
||||
/* task_work must only be added once */
|
||||
if (test_and_set_bit(0, &tctx->tw_pending))
|
||||
return;
|
||||
|
||||
if (likely(!task_work_add(tctx->task, &tctx->task_work, ctx->notify_method)))
|
||||
return;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user