recv/rw select-buffer fortifying
cover recv/rw select-buffer fortifying
This series makes selected buffer managment more resilient to errors, especially io_recv[msg](). Even though, it makes some small accidential optimisations, I don't think performance difference will be observable at the end.
Pavel Begunkov (7):
io_uring: indent left {send,recv}[msg]()
io_uring: remove extra checks in send/recv
io_uring: don't forget cflags in io_recv()
io_uring: free selected-bufs if error'ed
io_uring: move BUFFER_SELECT check into *recv[msg]
io_uring: extract io_put_kbuf() helper
io_uring: don't open-code recv kbuf managment
fs/io_uring.c | 363 +++++++++++++++++++++++++------------------------- 1 file changed, 182 insertions(+), 181 deletions(-)
Signature · 1 line
2.24.0
PATCH 1/7 io_uring: indent left {send,recv}[msg]()
Flip over "if (sock)" condition with return on error, the upper layer will take care. That change will be handy later, but already removes an extra jump from hot path.
--- fs/io_uring.c | 263 +++++++++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 133 deletions(-)
fs/io_uring.c +130 -133
@@ -3919,41 +3919,40 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)static int io_sendmsg (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { -struct io_async_msghdr *kmsg =NULL ; +struct io_async_msghdr iomsg, *kmsg =NULL ;struct socket *sock; +unsigned flags;int ret; sock =sock_from_file (req->file, &ret); -if (sock) { -struct io_async_msghdr iomsg; -unsigned flags; +if (unlikely (!sock)) +return ret; -if (req->io) { - kmsg = &req->io->msg; - kmsg->msg.msg_name = &req->io->msg.addr; -/* if iov is set, it's allocated already */ -if (!kmsg->iov) - kmsg->iov = kmsg->fast_iov; - kmsg->msg.msg_iter.iov = kmsg->iov; - }else { - ret =io_sendmsg_copy_hdr (req, &iomsg); -if (ret) -return ret; - kmsg = &iomsg; - } +if (req->io) { + kmsg = &req->io->msg; + kmsg->msg.msg_name = &req->io->msg.addr; +/* if iov is set, it's allocated already */ +if (!kmsg->iov) + kmsg->iov = kmsg->fast_iov; + kmsg->msg.msg_iter.iov = kmsg->iov; + }else { + ret =io_sendmsg_copy_hdr (req, &iomsg); +if (ret) +return ret; + kmsg = &iomsg; + } - flags = req->sr_msg.msg_flags; -if (flags &MSG_DONTWAIT ) - req->flags |=REQ_F_NOWAIT ; -else if (force_nonblock) - flags |=MSG_DONTWAIT ; + flags = req->sr_msg.msg_flags; +if (flags &MSG_DONTWAIT ) + req->flags |=REQ_F_NOWAIT ; +else if (force_nonblock) + flags |=MSG_DONTWAIT ; - ret =__sys_sendmsg_sock (sock, &kmsg->msg, flags); -if (force_nonblock && ret == -EAGAIN ) -return io_setup_async_msg (req, kmsg); -if (ret == -ERESTARTSYS ) - ret = -EINTR ; - } + ret =__sys_sendmsg_sock (sock, &kmsg->msg, flags); +if (force_nonblock && ret == -EAGAIN ) +return io_setup_async_msg (req, kmsg); +if (ret == -ERESTARTSYS ) + ret = -EINTR ;if (kmsg && kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov);
@@ -3967,39 +3966,38 @@ static int io_sendmsg(struct io_kiocb *req, bool force_nonblock,static int io_send (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { +struct io_sr_msg *sr = &req->sr_msg; +struct msghdr msg; +struct iovec iov;struct socket *sock; +unsigned flags;int ret; sock =sock_from_file (req->file, &ret); -if (sock) { -struct io_sr_msg *sr = &req->sr_msg; -struct msghdr msg; -struct iovec iov; -unsigned flags; +if (unlikely (!sock)) +return ret; - ret =import_single_range (WRITE , sr->buf, sr->len, &iov, - &msg.msg_iter); -if (ret) -return ret; + ret =import_single_range (WRITE , sr->buf, sr->len, &iov, &msg.msg_iter); +if (unlikely (ret)) +return ret; - msg.msg_name =NULL ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; - msg.msg_namelen =0 ; + msg.msg_name =NULL ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; + msg.msg_namelen =0 ; - flags = req->sr_msg.msg_flags; -if (flags &MSG_DONTWAIT ) - req->flags |=REQ_F_NOWAIT ; -else if (force_nonblock) - flags |=MSG_DONTWAIT ; + flags = req->sr_msg.msg_flags; +if (flags &MSG_DONTWAIT ) + req->flags |=REQ_F_NOWAIT ; +else if (force_nonblock) + flags |=MSG_DONTWAIT ; - msg.msg_flags = flags; - ret =sock_sendmsg (sock, &msg); -if (force_nonblock && ret == -EAGAIN ) -return -EAGAIN ; -if (ret == -ERESTARTSYS ) - ret = -EINTR ; - } + msg.msg_flags = flags; + ret =sock_sendmsg (sock, &msg); +if (force_nonblock && ret == -EAGAIN ) +return -EAGAIN ; +if (ret == -ERESTARTSYS ) + ret = -EINTR ;if (ret <0 )req_set_fail_links (req);
@@ -4152,62 +4150,62 @@ static int io_recvmsg_prep(struct io_kiocb *req,static int io_recvmsg (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { -struct io_async_msghdr *kmsg =NULL ; +struct io_async_msghdr iomsg, *kmsg =NULL ;struct socket *sock; +struct io_buffer *kbuf; +unsigned flags;int ret, cflags =0 ; sock =sock_from_file (req->file, &ret); -if (sock) { -struct io_buffer *kbuf; -struct io_async_msghdr iomsg; -unsigned flags; - -if (req->io) { - kmsg = &req->io->msg; - kmsg->msg.msg_name = &req->io->msg.addr; -/* if iov is set, it's allocated already */ -if (!kmsg->iov) - kmsg->iov = kmsg->fast_iov; - kmsg->msg.msg_iter.iov = kmsg->iov; - }else { - ret =io_recvmsg_copy_hdr (req, &iomsg); -if (ret) -return ret; - kmsg = &iomsg; - } +if (unlikely (!sock)) +return ret; - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); -if (IS_ERR (kbuf)) { -return PTR_ERR (kbuf); - }else if (kbuf) { - kmsg->fast_iov[0 ].iov_base =u64_to_user_ptr (kbuf->addr); -iov_iter_init (&kmsg->msg.msg_iter,READ , kmsg->iov, -1 , req->sr_msg.len); - } +if (req->io) { + kmsg = &req->io->msg; + kmsg->msg.msg_name = &req->io->msg.addr; +/* if iov is set, it's allocated already */ +if (!kmsg->iov) + kmsg->iov = kmsg->fast_iov; + kmsg->msg.msg_iter.iov = kmsg->iov; + }else { + ret =io_recvmsg_copy_hdr (req, &iomsg); +if (ret) +return ret; + kmsg = &iomsg; + } - flags = req->sr_msg.msg_flags; -if (flags &MSG_DONTWAIT ) - req->flags |=REQ_F_NOWAIT ; -else if (force_nonblock) - flags |=MSG_DONTWAIT ; + kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); +if (IS_ERR (kbuf)) { +return PTR_ERR (kbuf); + }else if (kbuf) { + kmsg->fast_iov[0 ].iov_base =u64_to_user_ptr (kbuf->addr); +iov_iter_init (&kmsg->msg.msg_iter,READ , kmsg->iov, +1 , req->sr_msg.len); + } - ret =__sys_recvmsg_sock (sock, &kmsg->msg, req->sr_msg.umsg, - kmsg->uaddr, flags); -if (force_nonblock && ret == -EAGAIN ) { - ret =io_setup_async_msg (req, kmsg); -if (ret != -EAGAIN ) -kfree (kbuf); -return ret; - } -if (ret == -ERESTARTSYS ) - ret = -EINTR ; -if (kbuf) + flags = req->sr_msg.msg_flags; +if (flags &MSG_DONTWAIT ) + req->flags |=REQ_F_NOWAIT ; +else if (force_nonblock) + flags |=MSG_DONTWAIT ; + + ret =__sys_recvmsg_sock (sock, &kmsg->msg, req->sr_msg.umsg, + kmsg->uaddr, flags); +if (force_nonblock && ret == -EAGAIN ) { + ret =io_setup_async_msg (req, kmsg); +if (ret != -EAGAIN )kfree (kbuf); +return ret; } +if (ret == -ERESTARTSYS ) + ret = -EINTR ; +if (kbuf) +kfree (kbuf);if (kmsg && kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov); req->flags &= ~REQ_F_NEED_CLEANUP ; +if (ret <0 )req_set_fail_links (req);__io_req_complete (req, ret, cflags, cs);
@@ -4218,51 +4216,50 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock, struct io_comp_state *cs) {struct io_buffer *kbuf =NULL ; +struct io_sr_msg *sr = &req->sr_msg; +struct msghdr msg; +void __user *buf = sr->buf;struct socket *sock; +struct iovec iov; +unsigned flags;int ret, cflags =0 ; sock =sock_from_file (req->file, &ret); -if (sock) { -struct io_sr_msg *sr = &req->sr_msg; -void __user *buf = sr->buf; -struct msghdr msg; -struct iovec iov; -unsigned flags; - - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); -if (IS_ERR (kbuf)) -return PTR_ERR (kbuf); -else if (kbuf) - buf =u64_to_user_ptr (kbuf->addr); +if (unlikely (!sock)) +return ret; - ret =import_single_range (READ , buf, sr->len, &iov, - &msg.msg_iter); -if (ret) { -kfree (kbuf); -return ret; - } + kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); +if (IS_ERR (kbuf)) +return PTR_ERR (kbuf); +else if (kbuf) + buf =u64_to_user_ptr (kbuf->addr); - req->flags |=REQ_F_NEED_CLEANUP ; - msg.msg_name =NULL ; - msg.msg_control =NULL ; - msg.msg_controllen =0 ; - msg.msg_namelen =0 ; - msg.msg_iocb =NULL ; - msg.msg_flags =0 ; - - flags = req->sr_msg.msg_flags; -if (flags &MSG_DONTWAIT ) - req->flags |=REQ_F_NOWAIT ; -else if (force_nonblock) - flags |=MSG_DONTWAIT ; - - ret =sock_recvmsg (sock, &msg, flags); -if (force_nonblock && ret == -EAGAIN ) -return -EAGAIN ; -if (ret == -ERESTARTSYS ) - ret = -EINTR ; + ret =import_single_range (READ , buf, sr->len, &iov, &msg.msg_iter); +if (unlikely (ret)) { +kfree (kbuf); +return ret; } + req->flags |=REQ_F_NEED_CLEANUP ; + msg.msg_name =NULL ; + msg.msg_control =NULL ; + msg.msg_controllen =0 ; + msg.msg_namelen =0 ; + msg.msg_iocb =NULL ; + msg.msg_flags =0 ; + + flags = req->sr_msg.msg_flags; +if (flags &MSG_DONTWAIT ) + req->flags |=REQ_F_NOWAIT ; +else if (force_nonblock) + flags |=MSG_DONTWAIT ; + + ret =sock_recvmsg (sock, &msg, flags); +if (force_nonblock && ret == -EAGAIN ) +return -EAGAIN ; +if (ret == -ERESTARTSYS ) + ret = -EINTR ; +kfree (kbuf); req->flags &= ~REQ_F_NEED_CLEANUP ;if (ret <0 )
Signature · 1 line
2.24.0
PATCH 2/7 io_uring: remove extra checks in send/recv
In reply to Pavel BegunkovWith the return on a bad socket, kmsg is always non-null by the end of the function, prune left extra checks and initialisations.
--- fs/io_uring.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
fs/io_uring.c +5 -5
@@ -3919,7 +3919,7 @@ static int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)static int io_sendmsg (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { -struct io_async_msghdr iomsg, *kmsg =NULL ; +struct io_async_msghdr iomsg, *kmsg;struct socket *sock;unsigned flags;int ret;
@@ -3954,7 +3954,7 @@ static int io_sendmsg(struct io_kiocb *req, bool force_nonblock,if (ret == -ERESTARTSYS ) ret = -EINTR ; -if (kmsg && kmsg->iov != kmsg->fast_iov) +if (kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov); req->flags &= ~REQ_F_NEED_CLEANUP ;if (ret <0 )
@@ -4150,7 +4150,7 @@ static int io_recvmsg_prep(struct io_kiocb *req,static int io_recvmsg (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { -struct io_async_msghdr iomsg, *kmsg =NULL ; +struct io_async_msghdr iomsg, *kmsg;struct socket *sock;struct io_buffer *kbuf;unsigned flags;
@@ -4202,7 +4202,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,if (kbuf)kfree (kbuf); -if (kmsg && kmsg->iov != kmsg->fast_iov) +if (kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov); req->flags &= ~REQ_F_NEED_CLEANUP ;
@@ -4215,7 +4215,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,static int io_recv (struct io_kiocb *req,bool force_nonblock,struct io_comp_state *cs) { -struct io_buffer *kbuf =NULL ; +struct io_buffer *kbuf;struct io_sr_msg *sr = &req->sr_msg;struct msghdr msg;void __user *buf = sr->buf;
Signature · 1 line
2.24.0
PATCH 3/7 io_uring: don't forget cflags in io_recv()
In reply to Pavel BegunkovInstead of returning error from io_recv(), go through generic cleanup path, because it'll retain cflags for userspace. Do the same for io_send() for consistency.
--- fs/io_uring.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
fs/io_uring.c +4 -6
@@ -3979,7 +3979,7 @@ static int io_send(struct io_kiocb *req, bool force_nonblock, ret =import_single_range (WRITE , sr->buf, sr->len, &iov, &msg.msg_iter);if (unlikely (ret)) -return ret; +return ret;; msg.msg_name =NULL ; msg.msg_control =NULL ;
@@ -4235,10 +4235,8 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock, buf =u64_to_user_ptr (kbuf->addr); ret =import_single_range (READ , buf, sr->len, &iov, &msg.msg_iter); -if (unlikely (ret)) { -kfree (kbuf); -return ret; - } +if (unlikely (ret)) + goto out_free; req->flags |=REQ_F_NEED_CLEANUP ; msg.msg_name =NULL ;
@@ -4259,7 +4257,7 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,return -EAGAIN ;if (ret == -ERESTARTSYS ) ret = -EINTR ; - +out_free:kfree (kbuf); req->flags &= ~REQ_F_NEED_CLEANUP ;if (ret <0 )
Signature · 1 line
2.24.0
PATCH 4/7 io_uring: free selected-bufs if error'ed
In reply to Pavel Begunkovio_clean_op() may be skipped even if there is a selected io_buffer, that's because *select_buffer() funcions never set REQ_F_NEED_CLEANUP.
Trigger io_clean_op() when REQ_F_BUFFER_SELECTED is set as well, and and clear the flag if was freed out of it.
--- fs/io_uring.c | 85 ++++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 41 deletions(-)
fs/io_uring.c +44 -41
@@ -957,7 +957,7 @@ static void io_get_req_task(struct io_kiocb *req)static inline void io_clean_op (struct io_kiocb *req) { -if (req->flags &REQ_F_NEED_CLEANUP ) +if (req->flags & (REQ_F_NEED_CLEANUP |REQ_F_BUFFER_SELECTED ))__io_clean_op (req); }
@@ -1931,6 +1931,7 @@ static int io_put_kbuf(struct io_kiocb *req) cflags = kbuf->bid <<IORING_CQE_BUFFER_SHIFT ; cflags |=IORING_CQE_F_BUFFER ; req->rw.addr =0 ; + req->flags &= ~REQ_F_BUFFER_SELECTED ;kfree (kbuf);return cflags; }
@@ -4191,20 +4192,16 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock, ret =__sys_recvmsg_sock (sock, &kmsg->msg, req->sr_msg.umsg, kmsg->uaddr, flags); -if (force_nonblock && ret == -EAGAIN ) { - ret =io_setup_async_msg (req, kmsg); -if (ret != -EAGAIN ) -kfree (kbuf); -return ret; - } +if (force_nonblock && ret == -EAGAIN ) +return io_setup_async_msg (req, kmsg);if (ret == -ERESTARTSYS ) ret = -EINTR ; +if (kbuf)kfree (kbuf); -if (kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov); - req->flags &= ~REQ_F_NEED_CLEANUP ; + req->flags &= ~(REQ_F_NEED_CLEANUP |REQ_F_BUFFER_SELECTED );if (ret <0 )req_set_fail_links (req);
@@ -4238,7 +4235,6 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,if (unlikely (ret)) goto out_free; - req->flags |=REQ_F_NEED_CLEANUP ; msg.msg_name =NULL ; msg.msg_control =NULL ; msg.msg_controllen =0 ;
@@ -4258,7 +4254,8 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,if (ret == -ERESTARTSYS ) ret = -EINTR ; out_free: -kfree (kbuf); +if (kbuf) +kfree (kbuf); req->flags &= ~REQ_F_NEED_CLEANUP ;if (ret <0 )req_set_fail_links (req);
@@ -5426,39 +5423,45 @@ static void __io_clean_op(struct io_kiocb *req) {struct io_async_ctx *io = req->io; -switch (req->opcode) { -case IORING_OP_READV : -case IORING_OP_READ_FIXED : -case IORING_OP_READ : -if (req->flags &REQ_F_BUFFER_SELECTED ) +if (req->flags &REQ_F_BUFFER_SELECTED ) { +switch (req->opcode) { +case IORING_OP_READV : +case IORING_OP_READ_FIXED : +case IORING_OP_READ :kfree ((void *)(unsigned long )req->rw.addr); -/* fallthrough */ -case IORING_OP_WRITEV : -case IORING_OP_WRITE_FIXED : -case IORING_OP_WRITE : -if (io->rw.iov != io->rw.fast_iov) -kfree (io->rw.iov); -break ; -case IORING_OP_RECVMSG : -if (req->flags &REQ_F_BUFFER_SELECTED ) -kfree (req->sr_msg.kbuf); -/* fallthrough */ -case IORING_OP_SENDMSG : -if (io->msg.iov != io->msg.fast_iov) -kfree (io->msg.iov); -break ; -case IORING_OP_RECV : -if (req->flags &REQ_F_BUFFER_SELECTED ) +break ; +case IORING_OP_RECVMSG : +case IORING_OP_RECV :kfree (req->sr_msg.kbuf); -break ; -case IORING_OP_SPLICE : -case IORING_OP_TEE : -io_put_file (req, req->splice.file_in, - (req->splice.flags &SPLICE_F_FD_IN_FIXED )); -break ; +break ; + } + req->flags &= ~REQ_F_BUFFER_SELECTED ; + } + +if (req->flags &REQ_F_NEED_CLEANUP ) { +switch (req->opcode) { +case IORING_OP_READV : +case IORING_OP_READ_FIXED : +case IORING_OP_READ : +case IORING_OP_WRITEV : +case IORING_OP_WRITE_FIXED : +case IORING_OP_WRITE : +if (io->rw.iov != io->rw.fast_iov) +kfree (io->rw.iov); +break ; +case IORING_OP_RECVMSG : +case IORING_OP_SENDMSG : +if (io->msg.iov != io->msg.fast_iov) +kfree (io->msg.iov); +break ; +case IORING_OP_SPLICE : +case IORING_OP_TEE : +io_put_file (req, req->splice.file_in, + (req->splice.flags &SPLICE_F_FD_IN_FIXED )); +break ; + } + req->flags &= ~REQ_F_NEED_CLEANUP ; } - - req->flags &= ~REQ_F_NEED_CLEANUP ; } static int io_issue_sqe(struct io_kiocb *req, const struct io_uring_sqe *sqe,
Signature · 1 line
2.24.0
PATCH 5/7 io_uring: move BUFFER_SELECT check into *recv[msg]
In reply to Pavel BegunkovMove REQ_F_BUFFER_SELECT flag check out of io_recv_buffer_select(), and do that in its call sites That saves us from double error checking and possibly an extra func call.
--- fs/io_uring.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-)
fs/io_uring.c +10 -12
@@ -4101,9 +4101,6 @@ static struct io_buffer *io_recv_buffer_select(struct io_kiocb *req,struct io_sr_msg *sr = &req->sr_msg;struct io_buffer *kbuf; -if (!(req->flags &REQ_F_BUFFER_SELECT )) -return NULL ; - kbuf =io_buffer_select (req, &sr->len, sr->bgid, sr->kbuf, needs_lock);if (IS_ERR (kbuf))return kbuf;
@@ -4153,7 +4150,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock, {struct io_async_msghdr iomsg, *kmsg;struct socket *sock; -struct io_buffer *kbuf; +struct io_buffer *kbuf =NULL ;unsigned flags;int ret, cflags =0 ;
@@ -4175,10 +4172,10 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock, kmsg = &iomsg; } - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); -if (IS_ERR (kbuf)) { -return PTR_ERR (kbuf); - }else if (kbuf) { +if (req->flags &REQ_F_BUFFER_SELECT ) { + kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); +if (IS_ERR (kbuf)) +return PTR_ERR (kbuf); kmsg->fast_iov[0 ].iov_base =u64_to_user_ptr (kbuf->addr);iov_iter_init (&kmsg->msg.msg_iter,READ , kmsg->iov,1 , req->sr_msg.len);
@@ -4225,11 +4222,12 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,if (unlikely (!sock))return ret; - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); -if (IS_ERR (kbuf)) -return PTR_ERR (kbuf); -else if (kbuf) +if (req->flags &REQ_F_BUFFER_SELECT ) { + kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); +if (IS_ERR (kbuf)) +return PTR_ERR (kbuf); buf =u64_to_user_ptr (kbuf->addr); + } ret =import_single_range (READ , buf, sr->len, &iov, &msg.msg_iter);if (unlikely (ret))
Signature · 1 line
2.24.0
PATCH 6/7 io_uring: extract io_put_kbuf() helper
In reply to Pavel BegunkovExtract a common helper for cleaning up a selected buffer, this will be used shortly. By the way, correct cflags types to unsigned and, as kbufs are anyway tracked by a flag, remove useless zeroing req->rw.addr.
--- fs/io_uring.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
fs/io_uring.c +12 -7
@@ -1922,20 +1922,25 @@ static inline unsigned int io_sqring_entries(struct io_ring_ctx *ctx)return smp_load_acquire (&rings->sq.tail) - ctx->cached_sq_head; } -static int io_put_kbuf (struct io_kiocb *req) +static unsigned int io_put_kbuf (struct io_kiocb *req,struct io_buffer *kbuf) { -struct io_buffer *kbuf; -int cflags; +unsigned int cflags; - kbuf = (struct io_buffer *) (unsigned long ) req->rw.addr; cflags = kbuf->bid <<IORING_CQE_BUFFER_SHIFT ; cflags |=IORING_CQE_F_BUFFER ; - req->rw.addr =0 ; req->flags &= ~REQ_F_BUFFER_SELECTED ;kfree (kbuf);return cflags; } +static inline unsigned int io_put_rw_kbuf (struct io_kiocb *req) +{ +struct io_buffer *kbuf; + + kbuf = (struct io_buffer *) (unsigned long ) req->rw.addr; +return io_put_kbuf (req, kbuf); +} +static inline bool io_run_task_work (void ) {if (current->task_works) {
@@ -1985,7 +1990,7 @@ static void io_iopoll_complete(struct io_ring_ctx *ctx, unsigned int *nr_events,list_del (&req->inflight_entry);if (req->flags &REQ_F_BUFFER_SELECTED ) - cflags =io_put_kbuf (req); + cflags =io_put_rw_kbuf (req);__io_cqring_fill_event (req, req->result, cflags); (*nr_events)++;
@@ -2177,7 +2182,7 @@ static void io_complete_rw_common(struct kiocb *kiocb, long res,if (res != req->result)req_set_fail_links (req);if (req->flags &REQ_F_BUFFER_SELECTED ) - cflags =io_put_kbuf (req); + cflags =io_put_rw_kbuf (req);__io_req_complete (req, res, cflags, cs); }
Signature · 1 line
2.24.0
PATCH 7/7 io_uring: don't open-code recv kbuf managment
In reply to Pavel BegunkovDon't implement fast path of kbuf free'ing and management inlined into io_recv{,msg}(), that's error prone and duplicates handling. Replace it with a helper io_put_recv_kbuf(), which mimics io_put_rw_kbuf() in the io_read/write().
This also keeps cflags calculation in one place, removing duplication between rw and recv/send.
--- fs/io_uring.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
fs/io_uring.c +14 -14
@@ -4101,7 +4101,7 @@ static int io_recvmsg_copy_hdr(struct io_kiocb *req, }static struct io_buffer *io_recv_buffer_select (struct io_kiocb *req, -int *cflags,bool needs_lock) +bool needs_lock) {struct io_sr_msg *sr = &req->sr_msg;struct io_buffer *kbuf;
@@ -4112,12 +4112,14 @@ static struct io_buffer *io_recv_buffer_select(struct io_kiocb *req, sr->kbuf = kbuf; req->flags |=REQ_F_BUFFER_SELECTED ; - - *cflags = kbuf->bid <<IORING_CQE_BUFFER_SHIFT ; - *cflags |=IORING_CQE_F_BUFFER ;return kbuf; } +static inline unsigned int io_put_recv_kbuf (struct io_kiocb *req) +{ +return io_put_kbuf (req, req->sr_msg.kbuf); +} +static int io_recvmsg_prep (struct io_kiocb *req,const struct io_uring_sqe *sqe) {
@@ -4155,7 +4157,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock, {struct io_async_msghdr iomsg, *kmsg;struct socket *sock; -struct io_buffer *kbuf =NULL ; +struct io_buffer *kbuf;unsigned flags;int ret, cflags =0 ;
@@ -4178,7 +4180,7 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock, }if (req->flags &REQ_F_BUFFER_SELECT ) { - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); + kbuf =io_recv_buffer_select (req, !force_nonblock);if (IS_ERR (kbuf))return PTR_ERR (kbuf); kmsg->fast_iov[0 ].iov_base =u64_to_user_ptr (kbuf->addr);
@@ -4199,12 +4201,11 @@ static int io_recvmsg(struct io_kiocb *req, bool force_nonblock,if (ret == -ERESTARTSYS ) ret = -EINTR ; -if (kbuf) -kfree (kbuf); +if (req->flags &REQ_F_BUFFER_SELECTED ) + cflags =io_put_recv_kbuf (req);if (kmsg->iov != kmsg->fast_iov)kfree (kmsg->iov); - req->flags &= ~(REQ_F_NEED_CLEANUP |REQ_F_BUFFER_SELECTED ); - + req->flags &= ~REQ_F_NEED_CLEANUP ;if (ret <0 )req_set_fail_links (req);__io_req_complete (req, ret, cflags, cs);
@@ -4228,7 +4229,7 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,return ret;if (req->flags &REQ_F_BUFFER_SELECT ) { - kbuf =io_recv_buffer_select (req, &cflags, !force_nonblock); + kbuf =io_recv_buffer_select (req, !force_nonblock);if (IS_ERR (kbuf))return PTR_ERR (kbuf); buf =u64_to_user_ptr (kbuf->addr);
@@ -4257,9 +4258,8 @@ static int io_recv(struct io_kiocb *req, bool force_nonblock,if (ret == -ERESTARTSYS ) ret = -EINTR ; out_free: -if (kbuf) -kfree (kbuf); - req->flags &= ~REQ_F_NEED_CLEANUP ; +if (req->flags &REQ_F_BUFFER_SELECTED ) + cflags =io_put_recv_kbuf (req);if (ret <0 )req_set_fail_links (req);__io_req_complete (req, ret, cflags, cs);
Signature · 1 line
2.24.0
Jens Axboe
maintainerQuoted 4 lines · Pavel Begunkov
This series makes selected buffer managment more resilient to errors, especially io_recv[msg](). Even though, it makes some small accidential optimisations, I don't think performance difference will be observable at the end.
I shuffled this a little bit, as it relies on both 5.9 and the leak fix from 5.8.
Also, some of your commit messages use really short lines, just use 72 consistently for all of them. Minor detail, just not sure why they are different. I fixed them up.
Signature · 1 line
Jens Axboe
Quoted 6 lines · Jens Axboe
Quoted 4 lines · Pavel Begunkov
This series makes selected buffer managment more resilient to errors, especially io_recv[msg](). Even though, it makes some small accidential optimisations, I don't think performance difference will be observable at the end.
Quoted 6 lines
I shuffled this a little bit, as it relies on both 5.9 and the leak fix from 5.8.
Also, some of your commit messages use really short lines, just use 72 consistently for all of them. Minor detail, just not sure why they are different. I fixed them up.
I'll double check the next time, thanks
Signature · 1 line
Pavel Begunkov