Pull io_uring fixes from Jens Axboe: - Small series sanitizing the locking done for either modifying or reading a chain of requests - If the application has a pid namespace, ensure that the sqthread pid is correctly printed in fdinfo - Fix for a hashing issue in the io-wq thread pool, which could lead to a use-after-free - Kill dead argument from io_prep_rw_pi() - Fix for a missed validation of the CQ ring head, affecting CQE refill * tag 'io_uring-7.1-20260515' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: io_uring: validate user-controlled cq.head in io_cqe_cache_refill() io-wq: check that the predecessor is hashed in io_wq_remove_pending() io_uring/rw: drop unused attr_type_mask from io_prep_rw_pi() io_uring: hold uring_lock across io_kill_timeouts() in cancel path io_uring: defer linked-timeout chain splice out of hrtimer context io_uring: hold uring_lock when walking link chain in io_wq_free_work() io_uring/fdinfo: translate SqThread PID through caller's pid_ns
Unified · Split
| @@ -561,8 +561,8 @@ __cold bool io_uring_try_cancel_requests(struct io_ring_ctx *ctx, · 560 unmodified lines | ||
| 561 | 561 | ret |= io_waitid_remove_all(ctx, tctx, cancel_all); |
| 562 | 562 | ret |= io_futex_remove_all(ctx, tctx, cancel_all); |
| 563 | 563 | ret |= io_uring_try_cancel_uring_cmd(ctx, tctx, cancel_all); |
| 564 | − mutex_unlock(&ctx->uring_lock); | |
| 565 | 564 | ret |= io_kill_timeouts(ctx, tctx, cancel_all); |
| 565 | + mutex_unlock(&ctx->uring_lock); | |
| 566 | 566 | if (tctx) |
| 567 | 567 | ret |= io_run_task_work() > 0; |
| 568 | 568 | else |
| @@ -190,8 +190,9 @@ static void __io_uring_show_fdinfo(struct io_ring_ctx *ctx, struct seq_file *m) · 189 unmodified lines | ||
| 190 | 190 | get_task_struct(tsk); |
| 191 | 191 | rcu_read_unlock(); |
| 192 | 192 | usec = io_sq_cpu_usec(tsk); |
| 193 | + sq_pid = task_pid_nr_ns(tsk, | |
| 194 | + proc_pid_ns(file_inode(m->file)->i_sb)); | |
| 193 | 195 | put_task_struct(tsk); |
| 194 | − sq_pid = sq->task_pid; | |
| 195 | 196 | sq_cpu = sq->sq_cpu; |
| 196 | 197 | sq_total_time = usec; |
| 197 | 198 | sq_work_time = sq->work_time; |
| @@ -1124,7 +1124,8 @@ static inline void io_wq_remove_pending(struct io_wq *wq, · 1123 unmodified lines | ||
| 1124 | 1124 | if (io_wq_is_hashed(work) && work == wq->hash_tail[hash]) { |
| 1125 | 1125 | if (prev) |
| 1126 | 1126 | prev_work = container_of(prev, struct io_wq_work, list); |
| 1127 | − if (prev_work && io_get_work_hash(prev_work) == hash) | |
| 1127 | + if (prev_work && io_wq_is_hashed(prev_work) && | |
| 1128 | + io_get_work_hash(prev_work) == hash) | |
| 1128 | 1129 | wq->hash_tail[hash] = prev_work; |
| 1129 | 1130 | else |
| 1130 | 1131 | wq->hash_tail[hash] = NULL; |
| @@ -686,13 +686,27 @@ static struct io_overflow_cqe *io_alloc_ocqe(struct io_ring_ctx *ctx, · 685 unmodified lines | ||
| 686 | 686 | return ocqe; |
| 687 | 687 | } |
| 688 | 688 | |
| 689 | +/* | |
| 690 | + * Compute queued CQEs for free-space calculation, clamped to cq_entries. | |
| 691 | + */ | |
| 692 | +static unsigned int io_cqring_queued(struct io_ring_ctx *ctx) | |
| 693 | +{ | |
| 694 | + struct io_rings *rings = io_get_rings(ctx); | |
| 695 | + int diff; | |
| 696 | + | |
| 697 | + diff = (int)(ctx->cached_cq_tail - READ_ONCE(rings->cq.head)); | |
| 698 | + if (diff >= 0) | |
| 699 | + return min((unsigned int)diff, ctx->cq_entries); | |
| 700 | + return 0; | |
| 701 | +} | |
| 702 | + | |
| 689 | 703 | /* |
| 690 | 704 | * Fill an empty dummy CQE, in case alignment is off for posting a 32b CQE |
| 691 | 705 | * because the ring is a single 16b entry away from wrapping. |
| 692 | 706 | */ |
| 693 | 707 | static bool io_fill_nop_cqe(struct io_ring_ctx *ctx, unsigned int off) |
| 694 | 708 | { |
| 695 | − if (__io_cqring_events(ctx) < ctx->cq_entries) { | |
| 709 | + if (io_cqring_queued(ctx) < ctx->cq_entries) { | |
| 696 | 710 | struct io_uring_cqe *cqe = &ctx->rings->cqes[off]; |
| 697 | 711 | |
| 698 | 712 | cqe->user_data = 0; |
| @@ -713,7 +727,7 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32) · 14 unmodified lines | ||
| 713 | 727 | { |
| 714 | 728 | struct io_rings *rings = ctx->rings; |
| 715 | 729 | unsigned int off = ctx->cached_cq_tail & (ctx->cq_entries - 1); |
| 716 | − unsigned int free, queued, len; | |
| 730 | + unsigned int free, len; | |
| 717 | 731 | |
| 718 | 732 | /* |
| 719 | 733 | * Posting into the CQ when there are pending overflowed CQEs may break |
| @@ -733,9 +747,7 @@ bool io_cqe_cache_refill(struct io_ring_ctx *ctx, bool overflow, bool cqe32) · 13 unmodified lines | ||
| 733 | 747 | off = 0; |
| 734 | 748 | } |
| 735 | 749 | |
| 736 | − /* userspace may cheat modifying the tail, be safe and do min */ | |
| 737 | − queued = min(__io_cqring_events(ctx), ctx->cq_entries); | |
| 738 | − free = ctx->cq_entries - queued; | |
| 750 | + free = ctx->cq_entries - io_cqring_queued(ctx); | |
| 739 | 751 | /* we need a contiguous range, limit based on the current array offset */ |
| 740 | 752 | len = min(free, ctx->cq_entries - off); |
| 741 | 753 | if (len < (cqe32 + 1)) |
| @@ -1452,8 +1464,13 @@ struct io_wq_work *io_wq_free_work(struct io_wq_work *work) · 710 unmodified lines | ||
| 1452 | 1464 | struct io_kiocb *nxt = NULL; |
| 1453 | 1465 | |
| 1454 | 1466 | if (req_ref_put_and_test_atomic(req)) { |
| 1455 | − if (req->flags & IO_REQ_LINK_FLAGS) | |
| 1467 | + if (req->flags & IO_REQ_LINK_FLAGS) { | |
| 1468 | + struct io_ring_ctx *ctx = req->ctx; | |
| 1469 | + | |
| 1470 | + mutex_lock(&ctx->uring_lock); | |
| 1456 | 1471 | nxt = io_req_find_next(req); |
| 1472 | + mutex_unlock(&ctx->uring_lock); | |
| 1473 | + } | |
| 1457 | 1474 | io_free_req(req); |
| 1458 | 1475 | } |
| 1459 | 1476 | return nxt ? &nxt->work : NULL; |
| @@ -230,7 +230,7 @@ static inline void io_meta_restore(struct io_async_rw *io, struct kiocb *kiocb) · 229 unmodified lines | ||
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | static int io_prep_rw_pi(struct io_kiocb *req, struct io_rw *rw, int ddir, |
| 233 | − u64 attr_ptr, u64 attr_type_mask) | |
| 233 | + u64 attr_ptr) | |
| 234 | 234 | { |
| 235 | 235 | struct io_uring_attr_pi pi_attr; |
| 236 | 236 | struct io_async_rw *io; |
| @@ -305,7 +305,7 @@ static int __io_prep_rw(struct io_kiocb *req, const struct io_uring_sqe *sqe, · 68 unmodified lines | ||
| 305 | 305 | return -EINVAL; |
| 306 | 306 | |
| 307 | 307 | attr_ptr = READ_ONCE(sqe->attr_ptr); |
| 308 | − return io_prep_rw_pi(req, rw, ddir, attr_ptr, attr_type_mask); | |
| 308 | + return io_prep_rw_pi(req, rw, ddir, attr_ptr); | |
| 309 | 309 | } |
| 310 | 310 | return 0; |
| 311 | 311 | } |
| @@ -284,6 +284,10 @@ static struct io_kiocb *__io_disarm_linked_timeout(struct io_kiocb *req, · 283 unmodified lines | ||
| 284 | 284 | struct io_timeout *timeout = io_kiocb_to_cmd(link, struct io_timeout); |
| 285 | 285 | |
| 286 | 286 | io_remove_next_linked(req); |
| 287 | + | |
| 288 | + /* If this is NULL, then timer already claimed it and will complete it */ | |
| 289 | + if (!timeout->head) | |
| 290 | + return NULL; | |
| 287 | 291 | timeout->head = NULL; |
| 288 | 292 | if (hrtimer_try_to_cancel(&io->timer) != -1) { |
| 289 | 293 | list_del(&timeout->list); |
| @@ -367,6 +371,14 @@ static void io_req_task_link_timeout(struct io_tw_req tw_req, io_tw_token_t tw) · 77 unmodified lines | ||
| 367 | 371 | int ret; |
| 368 | 372 | |
| 369 | 373 | if (prev) { |
| 374 | + /* | |
| 375 | + * splice the linked timeout out of prev's chain if the regular | |
| 376 | + * completion path didn't already do it. | |
| 377 | + */ | |
| 378 | + if (prev->link == req) | |
| 379 | + prev->link = req->link; | |
| 380 | + req->link = NULL; | |
| 381 | + | |
| 370 | 382 | if (!tw.cancel) { |
| 371 | 383 | struct io_cancel_data cd = { |
| 372 | 384 | .ctx = req->ctx, |
| @@ -401,10 +413,10 @@ static enum hrtimer_restart io_link_timeout_fn(struct hrtimer *timer) · 28 unmodified lines | ||
| 401 | 413 | |
| 402 | 414 | /* |
| 403 | 415 | * We don't expect the list to be empty, that will only happen if we |
| 404 | − * race with the completion of the linked work. | |
| 416 | + * race with the completion of the linked work. Splice of prev is | |
| 417 | + * done in io_req_task_link_timeout(), if needed. | |
| 405 | 418 | */ |
| 406 | 419 | if (prev) { |
| 407 | − io_remove_next_linked(prev); | |
| 408 | 420 | if (!req_ref_inc_not_zero(prev)) |
| 409 | 421 | prev = NULL; |
| 410 | 422 | } |