io_uring-7.3-20260911

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmqj5fsQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgpmGsD/0W7eNXJd/tFNPOdDwTr1/3yciqYXw5QO5Q
 eb2SLyr34sAODOItTYoBrIZ5b1Mbgm0yhT1wJ3YrVKLNLVSvbDPNtx5qtnAGcKvm
 09XsPmvlDcW8JLRsjd5dcsP+EDmgTNLuNGSeVycuTG91f5VD63vPHTKUhgKDabtC
 InM1LbIs2rz0tojdV6n4MOOF2AwZAOHqFtac+cQUCwuJhNtwUFClSUHxqYoP+JzE
 97ores3f+ArAtmOoVeH2wSCZTmwdB7MxOB8jmt8fdNSprW8nxTO3oT/eQzYXvlM9
 7LRJV/6SGVsWjuoEHAfW8G0p+JOzGGFvFIXGWEBenjtNmlyXJqfxYhkcLMw826ob
 pct3Rc5nheZbxKdCkHnY1AmEibS/c1kTZbDvSBXk9GLBKyQuI7B3yo163zMs3JjO
 YSAlLllDjdzOR6gCPg5HHZlywBWtXveC/xVBzDq7b1q07ysHFNO1yQplMM3U8sC0
 Eic4RcFU4ld+/L2GmbdgRZ9ataZsju+RFojSogA0NzR18HqVNQuZiVbY764GSop9
 HVW28lzoYamgvg5fLWJPrzJmdFrj/p8pi+cw1dK8uMk9VnFwdA740Nfhz1NWFS0Y
 TpvJtxc0f2ofrI1ilaa95vHC+wMyds1zxq9Bf4i9cgIhT17WqvE4SD0JMXmvza4k
 Yi72jzTTfQ==
 =zpCb
 -----END PGP SIGNATURE-----

Merge tag 'io_uring-7.3-20260911' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull io_uring fixes from Jens Axboe:

 - Fix a deadlock in the write path with superblock freezing

 - Fix an issue where a provided buffer ring would overconsume when
   using MSG_TRUNC

 - Keep the CQE flags on iopoll requests when adding kbuf flags

* tag 'io_uring-7.3-20260911' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
  io_uring/rw: keep CQE flags on iopoll requests when adding kbuf flags
  io_uring/net: don't overconsume buffers when using MSG_TRUNC
  io_uring/net: let io_recv_buf_select return the length of the buffer region
  io_uring/rw: end write accounting from ->ki_complete
This commit is contained in:
Linus Torvalds 2026-09-11 12:36:13 -07:00
commit 42f961c42b
2 changed files with 60 additions and 23 deletions

View File

@ -853,7 +853,7 @@ int io_recvmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
static inline bool io_recv_finish(struct io_kiocb *req,
struct io_async_msghdr *kmsg,
struct io_br_sel *sel, bool mshot_finished,
unsigned issue_flags)
unsigned issue_flags, int consumed)
{
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
unsigned int cflags = 0;
@ -877,7 +877,7 @@ static inline bool io_recv_finish(struct io_kiocb *req,
if (sr->flags & IORING_RECVSEND_BUNDLE) {
size_t this_ret = sel->val - sr->done_io;
cflags |= io_put_kbufs(req, this_ret, sel->buf_list, io_bundle_nbufs(kmsg, this_ret));
cflags |= io_put_kbufs(req, consumed, sel->buf_list, io_bundle_nbufs(kmsg, consumed));
if (sr->flags & IORING_RECV_RETRY)
cflags = req->cqe.flags | (cflags & CQE_F_MASK);
if (sr->mshot_len && sel->val >= sr->mshot_len)
@ -899,7 +899,7 @@ static inline bool io_recv_finish(struct io_kiocb *req,
return false;
}
} else {
cflags |= io_put_kbuf(req, sel->val, sel->buf_list);
cflags |= io_put_kbuf(req, consumed, sel->buf_list);
}
/*
@ -1027,6 +1027,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
int ret, min_ret = 0;
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
bool mshot_finished = true;
int consumed = 0;
size_t len;
sock = sock_from_file(req->file);
if (unlikely(!sock))
@ -1042,9 +1044,8 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
retry_multishot:
sel.buf_list = NULL;
len = sr->len;
if (io_do_buffer_select(req)) {
size_t len = sr->len;
sel = io_buffer_select(req, &len, sr->buf_group, issue_flags);
if (!sel.addr)
return -ENOBUFS;
@ -1065,6 +1066,7 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
if (req->flags & REQ_F_APOLL_MULTISHOT) {
ret = io_recvmsg_multishot(sock, sr, kmsg, flags,
&mshot_finished);
consumed = ret;
} else {
/* disable partial retry for recvmsg with cmsg attached */
if (flags & MSG_WAITALL && !kmsg->msg.msg_controllen)
@ -1072,6 +1074,15 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
ret = __sys_recvmsg_sock(sock, &kmsg->msg, sr->umsg,
kmsg->uaddr, flags);
/*
* With MSG_TRUNC, the net layer will return the full size of
* the packet, even if we only filled part of it in the buffers.
* Adjust the returned size to consume only the real part of the
* buffer.
*/
consumed = ret;
if (ret > 0)
consumed = min_t(size_t, ret, len);
}
if (ret < min_ret) {
@ -1098,7 +1109,7 @@ int io_recvmsg(struct io_kiocb *req, unsigned int issue_flags)
io_kbuf_recycle(req, sel.buf_list, issue_flags);
sel.val = ret;
if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags))
if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags, consumed))
goto retry_multishot;
return sel.val;
@ -1108,6 +1119,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg
struct io_br_sel *sel, unsigned int issue_flags)
{
struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg);
size_t len;
int ret;
/*
@ -1153,13 +1165,14 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg
/* special case 1 vec, can be a fast path */
if (ret == 1) {
sr->buf = arg.iovs[0].iov_base;
sr->len = arg.iovs[0].iov_len;
len = sr->len = arg.iovs[0].iov_len;
goto map_ubuf;
}
iov_iter_init(&kmsg->msg.msg_iter, ITER_DEST, arg.iovs, ret,
arg.out_len);
arg.out_len);
len = arg.out_len;
} else {
size_t len = sel->val;
len = sel->val;
*sel = io_buffer_select(req, &len, sr->buf_group, issue_flags);
if (!sel->addr)
@ -1173,7 +1186,7 @@ static int io_recv_buf_select(struct io_kiocb *req, struct io_async_msghdr *kmsg
return ret;
}
return 0;
return len;
}
int io_recv(struct io_kiocb *req, unsigned int issue_flags)
@ -1183,9 +1196,10 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
struct io_br_sel sel;
struct socket *sock;
unsigned flags;
int ret, min_ret = 0;
int ret, min_ret = 0, consumed = 0;
bool force_nonblock = issue_flags & IO_URING_F_NONBLOCK;
bool mshot_finished;
size_t len = 0;
sock = sock_from_file(req->file);
if (unlikely(!sock))
@ -1213,6 +1227,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
retry_multishot:
sel.buf_list = NULL;
len = sr->len;
if (io_do_buffer_select(req)) {
sel.val = sr->len;
ret = io_recv_buf_select(req, kmsg, &sel, issue_flags);
@ -1220,6 +1235,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
kmsg->msg.msg_inq = -1;
goto out_free;
}
len = ret;
sr->buf = NULL;
}
@ -1250,6 +1266,17 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
}
mshot_finished = ret <= 0;
/*
* With MSG_TRUNC, the net layer will return the full size of
* the packet, even if we only filled part of it in the buffers.
* Adjust the returned size to consume only the real part of the
* buffer.
*/
consumed = ret;
if (ret > 0)
consumed = min_t(size_t, ret, len);
if (ret > 0)
ret += sr->done_io;
else if (sr->done_io)
@ -1258,7 +1285,7 @@ int io_recv(struct io_kiocb *req, unsigned int issue_flags)
io_kbuf_recycle(req, sel.buf_list, issue_flags);
sel.val = ret;
if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags))
if (!io_recv_finish(req, kmsg, &sel, mshot_finished, issue_flags, consumed))
goto retry_multishot;
return sel.val;

View File

@ -517,20 +517,25 @@ static void io_req_end_write(struct io_kiocb *req)
}
}
/*
* Trigger the notifications after having done some IO, and finish the write
* accounting, if any.
*/
/* Trigger the notifications after having done some IO. */
static void io_req_io_notify(struct io_kiocb *req)
{
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
if (rw->kiocb.ki_flags & IOCB_WRITE)
fsnotify_modify(req->file);
else
fsnotify_access(req->file);
}
/* Finish write accounting and notify, for inline completions only. */
static void io_req_io_end(struct io_kiocb *req)
{
struct io_rw *rw = io_kiocb_to_cmd(req, struct io_rw);
if (rw->kiocb.ki_flags & IOCB_WRITE) {
if (rw->kiocb.ki_flags & IOCB_WRITE)
io_req_end_write(req);
fsnotify_modify(req->file);
} else {
fsnotify_access(req->file);
}
io_req_io_notify(req);
}
static void __io_complete_rw_common(struct io_kiocb *req, long res)
@ -563,7 +568,7 @@ void io_req_rw_complete(struct io_tw_req tw_req, io_tw_token_t tw)
{
struct io_kiocb *req = tw_req.req;
io_req_io_end(req);
io_req_io_notify(req);
if (req->flags & (REQ_F_BUFFER_SELECTED|REQ_F_BUFFER_RING))
req->cqe.flags |= io_put_kbuf(req, max(req->cqe.res, 0), NULL);
@ -577,6 +582,10 @@ static void io_complete_rw(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);
/* ring owner may block in freeze_super() before task_work runs */
if (kiocb->ki_flags & IOCB_WRITE)
io_req_end_write(req);
__io_complete_rw_common(req, res);
io_req_set_res(req, io_fixup_rw_res(req, res), 0);
req->io_task_work.func = io_req_rw_complete;
@ -871,6 +880,7 @@ static int io_rw_init_file(struct io_kiocb *req, fmode_t mode, int rw_type)
kiocb->private = NULL;
kiocb->ki_flags |= IOCB_HIPRI;
req->iopoll_completed = 0;
req->cqe.flags = 0;
if (ctx->flags & IORING_SETUP_HYBRID_IOPOLL) {
/* make sure every req only blocks once*/
req->flags &= ~REQ_F_IOPOLL_STATE;
@ -1373,7 +1383,7 @@ int io_do_iopoll(struct io_ring_ctx *ctx, bool force_nonspin)
list_del(&req->iopoll_node);
wq_list_add_tail(&req->comp_list, &ctx->submit_state.compl_reqs);
nr_events++;
req->cqe.flags = io_put_kbuf(req, max(req->cqe.res, 0), NULL);
req->cqe.flags |= io_put_kbuf(req, max(req->cqe.res, 0), NULL);
if (!io_is_uring_cmd(req))
io_req_rw_cleanup(req, 0);
}