2
0
mirror of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git synced 2025-09-04 20:19:47 +08:00

io_uring-6.16-20250606

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmhC8AkQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgprl3D/9i9py58aRdxBx8NthlWSFo7eP3F8IuYSmY
 Vt+Cfo9i2KuwQKfAeCtIYZIiFcNbqgeeMnJcTFPJv8c781b5bgVV9/J2HkQ0XykD
 ex8NdEqXQoaKqFLQWiv0lyEx8E0pMjlbqpSZMHzNacBcADGsWF3RHBYrcMyBsPTC
 UDuDe++Tph5jP2Mkqh73eWAWw2n+hzJ5frm5fuF2ShbNBexp5cq/9opBYeG7DWtz
 +6Ok9zUXdUkVXoNL9iiQa+T5dRSMIBh0tDQ7MT+yvHQ913MtyT9gXNFhfPlthG3U
 o3RiS/MQ8R0k4y2JmLoYwKP1dShmIkVkKXFaFpFTEdcZ2SBslolXCraVZDXx2L1i
 Wb6A1x5HNMgmYgwLmS7I9i/QuEgQqVsKM2ESoNke5tFlyizgzJOUn0czRR2dTMZg
 w10E0eeXIqD4c+x4t0wUQMcm0p6qEW47E8KB/QrmeSCufT7R6BuCUE4RFQKXgcLZ
 qUanG4UyeeBBxS/+vTDlSPuyi41YEmQz8yTIxvwgCtVbAtd10otldEVdYalUXEHO
 JH7K2Dw7lkwtsv/HM72pzvACFOjF37yv0mG1gK8FXWleG8gZQH1P0y7VqIHP+HcN
 HFESAbaaud9TNrCF36QdxiPRKH+jfAbFeAsa97b0pXOTQZ0OUxA7RVzYoN8Z+hh3
 Q/2sdDPjAw==
 =2eUI
 -----END PGP SIGNATURE-----

Merge tag 'io_uring-6.16-20250606' of git://git.kernel.dk/linux

Pull io_uring fixes from Jens Axboe:

 - Fix for a regression introduced in this merge window, where the 'id'
   passed to xa_find() for ifq lookup is uninitialized

 - Fix for zcrx release on registration failure. From 6.15, going to
   stable

 - Tweak for recv bundles, where msg_inq should be > 1 before being used
   to gate a retry event

 - Pavel doesnt want to be a maintainer anymore, remove him from the
   MAINTAINERS entry

 - Limit legacy kbuf registrations to 64k, which is the size of the
   buffer ID field anyway. Hence it's nonsensical to support more than
   that, and the only purpose that serves is to have syzbot trigger long
   exit delays for heavily configured debug kernels

 - Fix for the io_uring futex handling, which got broken for
   FUTEX2_PRIVATE by a generic futex commit adding private hashes

* tag 'io_uring-6.16-20250606' of git://git.kernel.dk/linux:
  io_uring/futex: mark wait requests as inflight
  io_uring/futex: get rid of struct io_futex addr union
  io_uring/kbuf: limit legacy provided buffer lists to USHRT_MAX
  MAINTAINERS: remove myself from io_uring
  io_uring/net: only consider msg_inq if larger than 1
  io_uring/zcrx: fix area release on registration failure
  io_uring/zcrx: init id for xa_find
This commit is contained in:
Linus Torvalds 2025-06-06 13:09:03 -07:00
commit 794a549207
8 changed files with 37 additions and 13 deletions

View File

@ -12670,7 +12670,6 @@ F: include/linux/iosys-map.h
IO_URING IO_URING
M: Jens Axboe <axboe@kernel.dk> M: Jens Axboe <axboe@kernel.dk>
M: Pavel Begunkov <asml.silence@gmail.com>
L: io-uring@vger.kernel.org L: io-uring@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.dk/linux-block T: git git://git.kernel.dk/linux-block

View File

@ -14,10 +14,7 @@
struct io_futex { struct io_futex {
struct file *file; struct file *file;
union { void __user *uaddr;
u32 __user *uaddr;
struct futex_waitv __user *uwaitv;
};
unsigned long futex_val; unsigned long futex_val;
unsigned long futex_mask; unsigned long futex_mask;
unsigned long futexv_owned; unsigned long futexv_owned;
@ -148,6 +145,8 @@ int io_futex_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
!futex_validate_input(iof->futex_flags, iof->futex_mask)) !futex_validate_input(iof->futex_flags, iof->futex_mask))
return -EINVAL; return -EINVAL;
/* Mark as inflight, so file exit cancelation will find it */
io_req_track_inflight(req);
return 0; return 0;
} }
@ -186,13 +185,15 @@ int io_futexv_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
if (!futexv) if (!futexv)
return -ENOMEM; return -ENOMEM;
ret = futex_parse_waitv(futexv, iof->uwaitv, iof->futex_nr, ret = futex_parse_waitv(futexv, iof->uaddr, iof->futex_nr,
io_futex_wakev_fn, req); io_futex_wakev_fn, req);
if (ret) { if (ret) {
kfree(futexv); kfree(futexv);
return ret; return ret;
} }
/* Mark as inflight, so file exit cancelation will find it */
io_req_track_inflight(req);
iof->futexv_owned = 0; iof->futexv_owned = 0;
iof->futexv_unqueued = 0; iof->futexv_unqueued = 0;
req->flags |= REQ_F_ASYNC_DATA; req->flags |= REQ_F_ASYNC_DATA;

View File

@ -408,7 +408,12 @@ static void io_clean_op(struct io_kiocb *req)
req->flags &= ~IO_REQ_CLEAN_FLAGS; req->flags &= ~IO_REQ_CLEAN_FLAGS;
} }
static inline void io_req_track_inflight(struct io_kiocb *req) /*
* Mark the request as inflight, so that file cancelation will find it.
* Can be used if the file is an io_uring instance, or if the request itself
* relies on ->mm being alive for the duration of the request.
*/
inline void io_req_track_inflight(struct io_kiocb *req)
{ {
if (!(req->flags & REQ_F_INFLIGHT)) { if (!(req->flags & REQ_F_INFLIGHT)) {
req->flags |= REQ_F_INFLIGHT; req->flags |= REQ_F_INFLIGHT;

View File

@ -83,6 +83,7 @@ void io_add_aux_cqe(struct io_ring_ctx *ctx, u64 user_data, s32 res, u32 cflags)
bool io_req_post_cqe(struct io_kiocb *req, s32 res, u32 cflags); bool io_req_post_cqe(struct io_kiocb *req, s32 res, u32 cflags);
void __io_commit_cqring_flush(struct io_ring_ctx *ctx); void __io_commit_cqring_flush(struct io_ring_ctx *ctx);
void io_req_track_inflight(struct io_kiocb *req);
struct file *io_file_get_normal(struct io_kiocb *req, int fd); struct file *io_file_get_normal(struct io_kiocb *req, int fd);
struct file *io_file_get_fixed(struct io_kiocb *req, int fd, struct file *io_file_get_fixed(struct io_kiocb *req, int fd,
unsigned issue_flags); unsigned issue_flags);

View File

@ -108,6 +108,7 @@ bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
buf = req->kbuf; buf = req->kbuf;
bl = io_buffer_get_list(ctx, buf->bgid); bl = io_buffer_get_list(ctx, buf->bgid);
list_add(&buf->list, &bl->buf_list); list_add(&buf->list, &bl->buf_list);
bl->nbufs++;
req->flags &= ~REQ_F_BUFFER_SELECTED; req->flags &= ~REQ_F_BUFFER_SELECTED;
io_ring_submit_unlock(ctx, issue_flags); io_ring_submit_unlock(ctx, issue_flags);
@ -122,6 +123,7 @@ static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list); kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
list_del(&kbuf->list); list_del(&kbuf->list);
bl->nbufs--;
if (*len == 0 || *len > kbuf->len) if (*len == 0 || *len > kbuf->len)
*len = kbuf->len; *len = kbuf->len;
if (list_empty(&bl->buf_list)) if (list_empty(&bl->buf_list))
@ -390,6 +392,7 @@ static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,
for (i = 0; i < nbufs && !list_empty(&bl->buf_list); i++) { for (i = 0; i < nbufs && !list_empty(&bl->buf_list); i++) {
nxt = list_first_entry(&bl->buf_list, struct io_buffer, list); nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
list_del(&nxt->list); list_del(&nxt->list);
bl->nbufs--;
kfree(nxt); kfree(nxt);
cond_resched(); cond_resched();
} }
@ -491,14 +494,24 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
{ {
struct io_buffer *buf; struct io_buffer *buf;
u64 addr = pbuf->addr; u64 addr = pbuf->addr;
int i, bid = pbuf->bid; int ret = -ENOMEM, i, bid = pbuf->bid;
for (i = 0; i < pbuf->nbufs; i++) { for (i = 0; i < pbuf->nbufs; i++) {
/*
* Nonsensical to have more than sizeof(bid) buffers in a
* buffer list, as the application then has no way of knowing
* which duplicate bid refers to what buffer.
*/
if (bl->nbufs == USHRT_MAX) {
ret = -EOVERFLOW;
break;
}
buf = kmalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT); buf = kmalloc(sizeof(*buf), GFP_KERNEL_ACCOUNT);
if (!buf) if (!buf)
break; break;
list_add_tail(&buf->list, &bl->buf_list); list_add_tail(&buf->list, &bl->buf_list);
bl->nbufs++;
buf->addr = addr; buf->addr = addr;
buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT); buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
buf->bid = bid; buf->bid = bid;
@ -508,7 +521,7 @@ static int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
cond_resched(); cond_resched();
} }
return i ? 0 : -ENOMEM; return i ? 0 : ret;
} }
static int __io_manage_buffers_legacy(struct io_kiocb *req, static int __io_manage_buffers_legacy(struct io_kiocb *req,

View File

@ -21,6 +21,9 @@ struct io_buffer_list {
struct list_head buf_list; struct list_head buf_list;
struct io_uring_buf_ring *buf_ring; struct io_uring_buf_ring *buf_ring;
}; };
/* count of classic/legacy buffers in buffer list */
int nbufs;
__u16 bgid; __u16 bgid;
/* below is for ring provided buffers */ /* below is for ring provided buffers */

View File

@ -832,7 +832,7 @@ static inline bool io_recv_finish(struct io_kiocb *req, int *ret,
* If more is available AND it was a full transfer, retry and * If more is available AND it was a full transfer, retry and
* append to this one * append to this one
*/ */
if (!sr->retry && kmsg->msg.msg_inq > 0 && this_ret > 0 && if (!sr->retry && kmsg->msg.msg_inq > 1 && this_ret > 0 &&
!iov_iter_count(&kmsg->msg.msg_iter)) { !iov_iter_count(&kmsg->msg.msg_iter)) {
req->cqe.flags = cflags & ~CQE_F_MASK; req->cqe.flags = cflags & ~CQE_F_MASK;
sr->len = kmsg->msg.msg_inq; sr->len = kmsg->msg.msg_inq;
@ -1070,7 +1070,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg
arg.mode |= KBUF_MODE_FREE; arg.mode |= KBUF_MODE_FREE;
} }
if (kmsg->msg.msg_inq > 0) if (kmsg->msg.msg_inq > 1)
arg.max_len = min_not_zero(sr->len, kmsg->msg.msg_inq); arg.max_len = min_not_zero(sr->len, kmsg->msg.msg_inq);
ret = io_buffers_peek(req, &arg); ret = io_buffers_peek(req, &arg);

View File

@ -366,7 +366,8 @@ static void io_free_rbuf_ring(struct io_zcrx_ifq *ifq)
static void io_zcrx_free_area(struct io_zcrx_area *area) static void io_zcrx_free_area(struct io_zcrx_area *area)
{ {
io_zcrx_unmap_area(area->ifq, area); if (area->ifq)
io_zcrx_unmap_area(area->ifq, area);
io_release_area_mem(&area->mem); io_release_area_mem(&area->mem);
kvfree(area->freelist); kvfree(area->freelist);
@ -631,12 +632,13 @@ ifq_free:
void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx) void io_unregister_zcrx_ifqs(struct io_ring_ctx *ctx)
{ {
struct io_zcrx_ifq *ifq; struct io_zcrx_ifq *ifq;
unsigned long id;
lockdep_assert_held(&ctx->uring_lock); lockdep_assert_held(&ctx->uring_lock);
while (1) { while (1) {
scoped_guard(mutex, &ctx->mmap_lock) { scoped_guard(mutex, &ctx->mmap_lock) {
unsigned long id = 0;
ifq = xa_find(&ctx->zcrx_ctxs, &id, ULONG_MAX, XA_PRESENT); ifq = xa_find(&ctx->zcrx_ctxs, &id, ULONG_MAX, XA_PRESENT);
if (ifq) if (ifq)
xa_erase(&ctx->zcrx_ctxs, id); xa_erase(&ctx->zcrx_ctxs, id);