// SPDX-License-Identifier: GPL-2.0#include <linux/kernel.h>#include <linux/errno.h>#include <linux/file.h>#include <linux/slab.h>#include <linux/net.h>#include <linux/un.h>#include <linux/compat.h>#include <net/compat.h>#include <linux/io_uring.h> #include <uapi/linux/io_uring.h> #include "filetable.h"#include "io_uring.h"#include "kbuf.h"#include "alloc_cache.h"#include "net.h"#include "notif.h"#include "rsrc.h"#include "zcrx.h" struct io_shutdown { struct file *file; int how;}; struct io_accept { struct file *file; struct sockaddr __user *addr; int __user *addr_len; int flags; int iou_flags; u32 file_slot; unsigned long nofile;}; struct io_socket { struct file *file; int domain; int type; int protocol; int flags; u32 file_slot; unsigned long nofile;}; struct io_connect { struct file *file; struct sockaddr __user *addr; int addr_len; bool in_progress; bool seen_econnaborted;}; struct io_bind { struct file *file; int addr_len;}; struct io_listen { struct file *file; int backlog;}; struct io_sr_msg { struct file *file; union { struct compat_msghdr __user *umsg_compat; struct user_msghdr __user *umsg; void __user *buf; }; int len; unsigned done_io; unsigned msg_flags; unsigned nr_multishot_loops; u16 flags; /* initialised and used only by !msg send variants */ u16 buf_group; /* per-invocation mshot limit */ unsigned mshot_len; /* overall mshot byte limit */ unsigned mshot_total_len; void __user *msg_control; /* used only for send zerocopy */ struct io_kiocb *notif;}; /* * The UAPI flags are the lower 8 bits, as that's all sqe->ioprio will hold * anyway. Use the upper 8 bits for internal uses. */enum sr_retry_flags { IORING_RECV_RETRY = (1U << 15), IORING_RECV_PARTIAL_MAP = (1U << 14), IORING_RECV_MSHOT_CAP = (1U << 13), IORING_RECV_MSHOT_LIM = (1U << 12), IORING_RECV_MSHOT_DONE = (1U << 11), IORING_RECV_RETRY_CLEAR = IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP, IORING_RECV_NO_RETRY = IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP | IORING_RECV_MSHOT_CAP | IORING_RECV_MSHOT_DONE,}; /* * Number of times we'll try and do receives if there's more data. If we * exceed this limit, then add us to the back of the queue and retry from * there. This helps fairness between flooding clients. */#define MULTISHOT_MAX_RETRY 32 struct io_recvzc { struct file *file; u16 flags; u32 len; struct io_zcrx_ifq *ifq;}; static int io_sg_from_iter_iovec(struct sk_buff *skb, struct iov_iter *from, size_t length);static int io_sg_from_iter(struct sk_buff *skb, struct iov_iter *from, size_t length); int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe){ struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown); if (unlikely(sqe->off || sqe->addr || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)) return -EINVAL; shutdown->how = READ_ONCE(sqe->len); req->flags |= REQ_F_FORCE_ASYNC; return 0;} int io_shutdown(struct io_kiocb *req, unsigned int issue_flags){ struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown); struct socket *sock; int ret; WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); sock = sock_from_file(req->file); if (unlikely(!sock)) return -ENOTSOCK; ret = __sys_shutdown_sock(sock, shutdown->how); io_req_set_res(req, ret, 0); return IOU_COMPLETE;} static bool io_net_retry(struct socket *sock, int flags){ if (!(flags & MSG_WAITALL)) return false; return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET;} static void io_netmsg_iovec_free(struct io_async_msghdr *kmsg){ if (kmsg->vec.iovec) io_vec_free(&kmsg->vec);} static void io_netmsg_recycle(struct io_kiocb *req, unsigned int issue_flags){ struct io_async_msghdr *hdr = req->async_data; /* can't recycle, ensure we free the iovec if we have one */ if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) { io_netmsg_iovec_free(hdr); return; } /* Let normal cleanup path reap it if we fail adding to the cache */ io_alloc_cache_vec_kasan(&hdr->vec); if (hdr->vec.nr > IO_VEC_CACHE_SOFT_CAP) io_vec_free(&hdr->vec); if (io_alloc_cache_put(&req->ctx->netmsg_cache, hdr)) io_req_async_data_clear(req, REQ_F_NEED_CLEANUP);} static struct io_async_msghdr *io_msg_alloc_async(struct io_kiocb *req){ struct io_ring_ctx *ctx = req->ctx; struct io_async_msghdr *hdr; hdr = io_uring_alloc_async_data(&ctx->netmsg_cache, req); if (!hdr) return NULL; /* If the async data was cached, we might have an iov cached inside. */ if (hdr->vec.iovec) req->flags |= REQ_F_NEED_CLEANUP; return hdr;} static inline void io_mshot_prep_retry(struct io_kiocb *req, struct io_async_msghdr *kmsg){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); req->flags &= ~REQ_F_BL_EMPTY; sr->done_io = 0; sr->flags &= ~IORING_RECV_RETRY_CLEAR; sr->len = sr->mshot_len;} static int io_net_import_vec(struct io_kiocb *req, struct io_async_msghdr *iomsg, const struct iovec __user *uiov, unsigned uvec_seg, int ddir){ struct iovec *iov; int ret, nr_segs; if (iomsg->vec.iovec) { nr_segs = iomsg->vec.nr; iov = iomsg->vec.iovec; } else { nr_segs = 1; iov = &iomsg->fast_iov; } ret = __import_iovec(ddir, uiov, uvec_seg, nr_segs, &iov, &iomsg->msg.msg_iter, io_is_compat(req->ctx)); if (unlikely(ret < 0)) return ret; if (iov) { req->flags |= REQ_F_NEED_CLEANUP; io_vec_reset_iovec(&iomsg->vec, iov, iomsg->msg.msg_iter.nr_segs); } return 0;} static int io_copy_msghdr_from_user(struct user_msghdr *msg, struct user_msghdr __user *umsg){ if (!user_access_begin(umsg, sizeof(*umsg))) return -EFAULT; unsafe_get_user(msg->msg_name, &umsg->msg_name, ua_end); unsafe_get_user(msg->msg_namelen, &umsg->msg_namelen, ua_end); unsafe_get_user(msg->msg_iov, &umsg->msg_iov, ua_end); unsafe_get_user(msg->msg_iovlen, &umsg->msg_iovlen, ua_end); unsafe_get_user(msg->msg_control, &umsg->msg_control, ua_end); unsafe_get_user(msg->msg_controllen, &umsg->msg_controllen, ua_end); user_access_end(); return 0;ua_end: user_access_end(); return -EFAULT;} static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg, struct user_msghdr *msg, struct sockaddr __user **save_addr){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); int ret; iomsg->msg.msg_name = &iomsg->addr; iomsg->msg.msg_iter.nr_segs = 0; if (io_is_compat(req->ctx)) { struct compat_msghdr cmsg; if (copy_from_user(&cmsg, sr->umsg_compat, sizeof(cmsg))) return -EFAULT; ret = __get_compat_msghdr(&iomsg->msg, &cmsg, save_addr); if (ret) return ret; memset(msg, 0, sizeof(*msg)); msg->msg_namelen = cmsg.msg_namelen; msg->msg_controllen = cmsg.msg_controllen; msg->msg_iov = compat_ptr(cmsg.msg_iov); msg->msg_iovlen = cmsg.msg_iovlen; } else { ret = io_copy_msghdr_from_user(msg, sr->umsg); if (unlikely(ret)) return ret; msg->msg_flags = 0; ret = __copy_msghdr(&iomsg->msg, msg, save_addr); if (ret) return ret; } if (req->flags & REQ_F_BUFFER_SELECT) { if (msg->msg_iovlen == 0) { sr->len = 0; } else if (msg->msg_iovlen > 1) { return -EINVAL; } else { struct iovec fast_iov, *iov; iov = iovec_from_user(msg->msg_iov, 1, 1, &fast_iov, io_is_compat(req->ctx)); if (IS_ERR(iov)) return PTR_ERR(iov); sr->len = iov->iov_len; } } return 0;} void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req){ struct io_async_msghdr *io = req->async_data; io_netmsg_iovec_free(io);} static int io_send_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); struct io_async_msghdr *kmsg = req->async_data; void __user *addr; u16 addr_len; int ret; sr->buf = u64_to_user_ptr(READ_ONCE(sqe->addr)); if (READ_ONCE(sqe->__pad3[0])) return -EINVAL; kmsg->msg.msg_name = NULL; kmsg->msg.msg_namelen = 0; kmsg->msg.msg_control = NULL; kmsg->msg.msg_controllen = 0; kmsg->msg.msg_ubuf = NULL; addr = u64_to_user_ptr(READ_ONCE(sqe->addr2)); addr_len = READ_ONCE(sqe->addr_len); if (addr) { ret = move_addr_to_kernel(addr, addr_len, &kmsg->addr); if (unlikely(ret < 0)) return ret; kmsg->msg.msg_name = &kmsg->addr; kmsg->msg.msg_namelen = addr_len; } if (sr->flags & IORING_RECVSEND_FIXED_BUF) { if (!(sr->flags & IORING_SEND_VECTORIZED)) { req->flags |= REQ_F_IMPORT_BUFFER; return 0; } kmsg->msg.msg_iter.nr_segs = sr->len; return io_prep_reg_iovec(req, &kmsg->vec, sr->buf, sr->len); } if (req->flags & REQ_F_BUFFER_SELECT) return 0; if (sr->flags & IORING_SEND_VECTORIZED) return io_net_import_vec(req, kmsg, sr->buf, sr->len, ITER_SOURCE); return import_ubuf(ITER_SOURCE, sr->buf, sr->len, &kmsg->msg.msg_iter);} static int io_sendmsg_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); struct io_async_msghdr *kmsg = req->async_data; struct user_msghdr msg; int ret; sr->flags |= IORING_SEND_VECTORIZED; sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr)); ret = io_msg_copy_hdr(req, kmsg, &msg, NULL); if (unlikely(ret)) return ret; /* save msg_control as sys_sendmsg() overwrites it */ sr->msg_control = kmsg->msg.msg_control_user; if (sr->flags & IORING_RECVSEND_FIXED_BUF) { kmsg->msg.msg_iter.nr_segs = msg.msg_iovlen; return io_prep_reg_iovec(req, &kmsg->vec, msg.msg_iov, msg.msg_iovlen); } if (req->flags & REQ_F_BUFFER_SELECT) return 0; return io_net_import_vec(req, kmsg, msg.msg_iov, msg.msg_iovlen, ITER_SOURCE);} #define SENDMSG_FLAGS (IORING_RECVSEND_POLL_FIRST | IORING_RECVSEND_BUNDLE | \ IORING_SEND_VECTORIZED | IORING_RECVSEND_FIXED_BUF) int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); sr->done_io = 0; sr->len = READ_ONCE(sqe->len); if (unlikely(sr->len < 0)) return -EINVAL; sr->flags = READ_ONCE(sqe->ioprio); if (sr->flags & ~SENDMSG_FLAGS) return -EINVAL; if (sr->flags & IORING_RECVSEND_FIXED_BUF) { /* registered buffer send only supported for plain IORING_OP_SEND */ if (req->opcode != IORING_OP_SEND || (req->flags & REQ_F_BUFFER_SELECT) || (sr->flags & (IORING_RECVSEND_BUNDLE|IORING_SEND_VECTORIZED))) return -EINVAL; req->buf_index = READ_ONCE(sqe->buf_index); } sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL; if (sr->msg_flags & MSG_DONTWAIT) req->flags |= REQ_F_NOWAIT; if (req->flags & REQ_F_BUFFER_SELECT) sr->buf_group = req->buf_index; sr->mshot_total_len = sr->mshot_len = 0; if (sr->flags & IORING_RECVSEND_BUNDLE) { if (req->opcode == IORING_OP_SENDMSG) return -EINVAL; sr->msg_flags |= MSG_WAITALL; req->flags |= REQ_F_MULTISHOT; } if (io_is_compat(req->ctx)) sr->msg_flags |= MSG_CMSG_COMPAT; if (unlikely(!io_msg_alloc_async(req))) return -ENOMEM; if (req->opcode != IORING_OP_SENDMSG) return io_send_setup(req, sqe); if (unlikely(sqe->addr2 || sqe->file_index)) return -EINVAL; return io_sendmsg_setup(req, sqe);} static void io_req_msg_cleanup(struct io_kiocb *req, unsigned int issue_flags){ io_netmsg_recycle(req, issue_flags);} /* * For bundle completions, we need to figure out how many segments we consumed. * A bundle could be using a single ITER_UBUF if that's all we mapped, or it * could be using an ITER_IOVEC. If the latter, then if we consumed all of * the segments, then it's a trivial questiont o answer. If we have residual * data in the iter, then loop the segments to figure out how much we * transferred. */static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret){ struct iovec *iov; int nbufs; /* no data is always zero segments, and a ubuf is always 1 segment */ if (ret <= 0) return 0; if (iter_is_ubuf(&kmsg->msg.msg_iter)) return 1; iov = kmsg->vec.iovec; if (!iov) iov = &kmsg->fast_iov; /* if all data was transferred, it's basic pointer math */ if (!iov_iter_count(&kmsg->msg.msg_iter)) return iter_iov(&kmsg->msg.msg_iter) - iov; /* short transfer, count segments */ nbufs = 0; do { int this_len = min_t(int, iov[nbufs].iov_len, ret); nbufs++; ret -= this_len; } while (ret); return nbufs;} static int io_net_kbuf_recyle(struct io_kiocb *req, struct io_buffer_list *bl, struct io_async_msghdr *kmsg, int len){ req->flags |= REQ_F_BL_NO_RECYCLE; if (req->flags & REQ_F_BUFFERS_COMMIT) io_kbuf_commit(req, bl, len, io_bundle_nbufs(kmsg, len)); return IOU_RETRY;} static inline bool io_send_finish(struct io_kiocb *req, struct io_async_msghdr *kmsg, struct io_br_sel *sel){ struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); bool bundle_finished = sel->val <= 0; unsigned int cflags; if (!(sr->flags & IORING_RECVSEND_BUNDLE)) { cflags = io_put_kbuf(req, sel->val, sel->buf_list);Lines 1–500 of 1947. Load more
// SPDX-License-Identifier: GPL-2.0 #include <linux/kernel.h> #include <linux/errno.h> #include <linux/file.h> #include <linux/slab.h> #include <linux/net.h> #include <linux/un.h> #include <linux/compat.h> #include <net/compat.h> #include <linux/io_uring.h> #include <uapi/linux/io_uring.h> #include "filetable.h" #include "io_uring.h" #include "kbuf.h" #include "alloc_cache.h" #include "net.h" #include "notif.h" #include "rsrc.h" #include "zcrx.h" struct io_shutdown { struct file *file; int how; }; struct io_accept { struct file *file; struct sockaddr __user *addr; int __user *addr_len; int flags; int iou_flags; u32 file_slot; unsigned long nofile; }; struct io_socket { struct file *file; int domain; int type; int protocol; int flags; u32 file_slot; unsigned long nofile; }; struct io_connect { struct file *file; struct sockaddr __user *addr; int addr_len; bool in_progress; bool seen_econnaborted; }; struct io_bind { struct file *file; int addr_len; }; struct io_listen { struct file *file; int backlog; }; struct io_sr_msg { struct file *file; union { struct compat_msghdr __user *umsg_compat; struct user_msghdr __user *umsg; void __user *buf; }; int len; unsigned done_io; unsigned msg_flags; unsigned nr_multishot_loops; u16 flags; /* initialised and used only by !msg send variants */ u16 buf_group; /* per-invocation mshot limit */ unsigned mshot_len; /* overall mshot byte limit */ unsigned mshot_total_len; void __user *msg_control; /* used only for send zerocopy */ struct io_kiocb *notif; }; /* * The UAPI flags are the lower 8 bits, as that's all sqe->ioprio will hold * anyway. Use the upper 8 bits for internal uses. */ enum sr_retry_flags { IORING_RECV_RETRY = (1U << 15), IORING_RECV_PARTIAL_MAP = (1U << 14), IORING_RECV_MSHOT_CAP = (1U << 13), IORING_RECV_MSHOT_LIM = (1U << 12), IORING_RECV_MSHOT_DONE = (1U << 11), IORING_RECV_RETRY_CLEAR = IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP, IORING_RECV_NO_RETRY = IORING_RECV_RETRY | IORING_RECV_PARTIAL_MAP | IORING_RECV_MSHOT_CAP | IORING_RECV_MSHOT_DONE, }; /* * Number of times we'll try and do receives if there's more data. If we * exceed this limit, then add us to the back of the queue and retry from * there. This helps fairness between flooding clients. */ #define MULTISHOT_MAX_RETRY 32 struct io_recvzc { struct file *file; u16 flags; u32 len; struct io_zcrx_ifq *ifq; }; static int io_sg_from_iter_iovec(struct sk_buff *skb, struct iov_iter *from, size_t length); static int io_sg_from_iter(struct sk_buff *skb, struct iov_iter *from, size_t length); int io_shutdown_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) { struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown); if (unlikely(sqe->off || sqe->addr || sqe->rw_flags || sqe->buf_index || sqe->splice_fd_in)) return -EINVAL; shutdown->how = READ_ONCE(sqe->len); req->flags |= REQ_F_FORCE_ASYNC; return 0; } int io_shutdown(struct io_kiocb *req, unsigned int issue_flags) { struct io_shutdown *shutdown = io_kiocb_to_cmd(req, struct io_shutdown); struct socket *sock; int ret; WARN_ON_ONCE(issue_flags & IO_URING_F_NONBLOCK); sock = sock_from_file(req->file); if (unlikely(!sock)) return -ENOTSOCK; ret = __sys_shutdown_sock(sock, shutdown->how); io_req_set_res(req, ret, 0); return IOU_COMPLETE; } static bool io_net_retry(struct socket *sock, int flags) { if (!(flags & MSG_WAITALL)) return false; return sock->type == SOCK_STREAM || sock->type == SOCK_SEQPACKET; } static void io_netmsg_iovec_free(struct io_async_msghdr *kmsg) { if (kmsg->vec.iovec) io_vec_free(&kmsg->vec); } static void io_netmsg_recycle(struct io_kiocb *req, unsigned int issue_flags) { struct io_async_msghdr *hdr = req->async_data; /* can't recycle, ensure we free the iovec if we have one */ if (unlikely(issue_flags & IO_URING_F_UNLOCKED)) { io_netmsg_iovec_free(hdr); return; } /* Let normal cleanup path reap it if we fail adding to the cache */ io_alloc_cache_vec_kasan(&hdr->vec); if (hdr->vec.nr > IO_VEC_CACHE_SOFT_CAP) io_vec_free(&hdr->vec); if (io_alloc_cache_put(&req->ctx->netmsg_cache, hdr)) io_req_async_data_clear(req, REQ_F_NEED_CLEANUP); } static struct io_async_msghdr *io_msg_alloc_async(struct io_kiocb *req) { struct io_ring_ctx *ctx = req->ctx; struct io_async_msghdr *hdr; hdr = io_uring_alloc_async_data(&ctx->netmsg_cache, req); if (!hdr) return NULL; /* If the async data was cached, we might have an iov cached inside. */ if (hdr->vec.iovec) req->flags |= REQ_F_NEED_CLEANUP; return hdr; } static inline void io_mshot_prep_retry(struct io_kiocb *req, struct io_async_msghdr *kmsg) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); req->flags &= ~REQ_F_BL_EMPTY; sr->done_io = 0; sr->flags &= ~IORING_RECV_RETRY_CLEAR; sr->len = sr->mshot_len; } static int io_net_import_vec(struct io_kiocb *req, struct io_async_msghdr *iomsg, const struct iovec __user *uiov, unsigned uvec_seg, int ddir) { struct iovec *iov; int ret, nr_segs; if (iomsg->vec.iovec) { nr_segs = iomsg->vec.nr; iov = iomsg->vec.iovec; } else { nr_segs = 1; iov = &iomsg->fast_iov; } ret = __import_iovec(ddir, uiov, uvec_seg, nr_segs, &iov, &iomsg->msg.msg_iter, io_is_compat(req->ctx)); if (unlikely(ret < 0)) return ret; if (iov) { req->flags |= REQ_F_NEED_CLEANUP; io_vec_reset_iovec(&iomsg->vec, iov, iomsg->msg.msg_iter.nr_segs); } return 0; } static int io_copy_msghdr_from_user(struct user_msghdr *msg, struct user_msghdr __user *umsg) { if (!user_access_begin(umsg, sizeof(*umsg))) return -EFAULT; unsafe_get_user(msg->msg_name, &umsg->msg_name, ua_end); unsafe_get_user(msg->msg_namelen, &umsg->msg_namelen, ua_end); unsafe_get_user(msg->msg_iov, &umsg->msg_iov, ua_end); unsafe_get_user(msg->msg_iovlen, &umsg->msg_iovlen, ua_end); unsafe_get_user(msg->msg_control, &umsg->msg_control, ua_end); unsafe_get_user(msg->msg_controllen, &umsg->msg_controllen, ua_end); user_access_end(); return 0; ua_end: user_access_end(); return -EFAULT; } static int io_msg_copy_hdr(struct io_kiocb *req, struct io_async_msghdr *iomsg, struct user_msghdr *msg, struct sockaddr __user **save_addr) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); int ret; iomsg->msg.msg_name = &iomsg->addr; iomsg->msg.msg_iter.nr_segs = 0; if (io_is_compat(req->ctx)) { struct compat_msghdr cmsg; if (copy_from_user(&cmsg, sr->umsg_compat, sizeof(cmsg))) return -EFAULT; ret = __get_compat_msghdr(&iomsg->msg, &cmsg, save_addr); if (ret) return ret; memset(msg, 0, sizeof(*msg)); msg->msg_namelen = cmsg.msg_namelen; msg->msg_controllen = cmsg.msg_controllen; msg->msg_iov = compat_ptr(cmsg.msg_iov); msg->msg_iovlen = cmsg.msg_iovlen; } else { ret = io_copy_msghdr_from_user(msg, sr->umsg); if (unlikely(ret)) return ret; msg->msg_flags = 0; ret = __copy_msghdr(&iomsg->msg, msg, save_addr); if (ret) return ret; } if (req->flags & REQ_F_BUFFER_SELECT) { if (msg->msg_iovlen == 0) { sr->len = 0; } else if (msg->msg_iovlen > 1) { return -EINVAL; } else { struct iovec fast_iov, *iov; iov = iovec_from_user(msg->msg_iov, 1, 1, &fast_iov, io_is_compat(req->ctx)); if (IS_ERR(iov)) return PTR_ERR(iov); sr->len = iov->iov_len; } } return 0; } void io_sendmsg_recvmsg_cleanup(struct io_kiocb *req) { struct io_async_msghdr *io = req->async_data; io_netmsg_iovec_free(io); } static int io_send_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); struct io_async_msghdr *kmsg = req->async_data; void __user *addr; u16 addr_len; int ret; sr->buf = u64_to_user_ptr(READ_ONCE(sqe->addr)); if (READ_ONCE(sqe->__pad3[0])) return -EINVAL; kmsg->msg.msg_name = NULL; kmsg->msg.msg_namelen = 0; kmsg->msg.msg_control = NULL; kmsg->msg.msg_controllen = 0; kmsg->msg.msg_ubuf = NULL; addr = u64_to_user_ptr(READ_ONCE(sqe->addr2)); addr_len = READ_ONCE(sqe->addr_len); if (addr) { ret = move_addr_to_kernel(addr, addr_len, &kmsg->addr); if (unlikely(ret < 0)) return ret; kmsg->msg.msg_name = &kmsg->addr; kmsg->msg.msg_namelen = addr_len; } if (sr->flags & IORING_RECVSEND_FIXED_BUF) { if (!(sr->flags & IORING_SEND_VECTORIZED)) { req->flags |= REQ_F_IMPORT_BUFFER; return 0; } kmsg->msg.msg_iter.nr_segs = sr->len; return io_prep_reg_iovec(req, &kmsg->vec, sr->buf, sr->len); } if (req->flags & REQ_F_BUFFER_SELECT) return 0; if (sr->flags & IORING_SEND_VECTORIZED) return io_net_import_vec(req, kmsg, sr->buf, sr->len, ITER_SOURCE); return import_ubuf(ITER_SOURCE, sr->buf, sr->len, &kmsg->msg.msg_iter); } static int io_sendmsg_setup(struct io_kiocb *req, const struct io_uring_sqe *sqe) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); struct io_async_msghdr *kmsg = req->async_data; struct user_msghdr msg; int ret; sr->flags |= IORING_SEND_VECTORIZED; sr->umsg = u64_to_user_ptr(READ_ONCE(sqe->addr)); ret = io_msg_copy_hdr(req, kmsg, &msg, NULL); if (unlikely(ret)) return ret; /* save msg_control as sys_sendmsg() overwrites it */ sr->msg_control = kmsg->msg.msg_control_user; if (sr->flags & IORING_RECVSEND_FIXED_BUF) { kmsg->msg.msg_iter.nr_segs = msg.msg_iovlen; return io_prep_reg_iovec(req, &kmsg->vec, msg.msg_iov, msg.msg_iovlen); } if (req->flags & REQ_F_BUFFER_SELECT) return 0; return io_net_import_vec(req, kmsg, msg.msg_iov, msg.msg_iovlen, ITER_SOURCE); } #define SENDMSG_FLAGS (IORING_RECVSEND_POLL_FIRST | IORING_RECVSEND_BUNDLE | \ IORING_SEND_VECTORIZED | IORING_RECVSEND_FIXED_BUF) int io_sendmsg_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); sr->done_io = 0; sr->len = READ_ONCE(sqe->len); if (unlikely(sr->len < 0)) return -EINVAL; sr->flags = READ_ONCE(sqe->ioprio); if (sr->flags & ~SENDMSG_FLAGS) return -EINVAL; if (sr->flags & IORING_RECVSEND_FIXED_BUF) { /* registered buffer send only supported for plain IORING_OP_SEND */ if (req->opcode != IORING_OP_SEND || (req->flags & REQ_F_BUFFER_SELECT) || (sr->flags & (IORING_RECVSEND_BUNDLE|IORING_SEND_VECTORIZED))) return -EINVAL; req->buf_index = READ_ONCE(sqe->buf_index); } sr->msg_flags = READ_ONCE(sqe->msg_flags) | MSG_NOSIGNAL; if (sr->msg_flags & MSG_DONTWAIT) req->flags |= REQ_F_NOWAIT; if (req->flags & REQ_F_BUFFER_SELECT) sr->buf_group = req->buf_index; sr->mshot_total_len = sr->mshot_len = 0; if (sr->flags & IORING_RECVSEND_BUNDLE) { if (req->opcode == IORING_OP_SENDMSG) return -EINVAL; sr->msg_flags |= MSG_WAITALL; req->flags |= REQ_F_MULTISHOT; } if (io_is_compat(req->ctx)) sr->msg_flags |= MSG_CMSG_COMPAT; if (unlikely(!io_msg_alloc_async(req))) return -ENOMEM; if (req->opcode != IORING_OP_SENDMSG) return io_send_setup(req, sqe); if (unlikely(sqe->addr2 || sqe->file_index)) return -EINVAL; return io_sendmsg_setup(req, sqe); } static void io_req_msg_cleanup(struct io_kiocb *req, unsigned int issue_flags) { io_netmsg_recycle(req, issue_flags); } /* * For bundle completions, we need to figure out how many segments we consumed. * A bundle could be using a single ITER_UBUF if that's all we mapped, or it * could be using an ITER_IOVEC. If the latter, then if we consumed all of * the segments, then it's a trivial questiont o answer. If we have residual * data in the iter, then loop the segments to figure out how much we * transferred. */ static int io_bundle_nbufs(struct io_async_msghdr *kmsg, int ret) { struct iovec *iov; int nbufs; /* no data is always zero segments, and a ubuf is always 1 segment */ if (ret <= 0) return 0; if (iter_is_ubuf(&kmsg->msg.msg_iter)) return 1; iov = kmsg->vec.iovec; if (!iov) iov = &kmsg->fast_iov; /* if all data was transferred, it's basic pointer math */ if (!iov_iter_count(&kmsg->msg.msg_iter)) return iter_iov(&kmsg->msg.msg_iter) - iov; /* short transfer, count segments */ nbufs = 0; do { int this_len = min_t(int, iov[nbufs].iov_len, ret); nbufs++; ret -= this_len; } while (ret); return nbufs; } static int io_net_kbuf_recyle(struct io_kiocb *req, struct io_buffer_list *bl, struct io_async_msghdr *kmsg, int len) { req->flags |= REQ_F_BL_NO_RECYCLE; if (req->flags & REQ_F_BUFFERS_COMMIT) io_kbuf_commit(req, bl, len, io_bundle_nbufs(kmsg, len)); return IOU_RETRY; } static inline bool io_send_finish(struct io_kiocb *req, struct io_async_msghdr *kmsg, struct io_br_sel *sel) { struct io_sr_msg *sr = io_kiocb_to_cmd(req, struct io_sr_msg); bool bundle_finished = sel->val <= 0; unsigned int cflags; if (!(sr->flags & IORING_RECVSEND_BUNDLE)) { cflags = io_put_kbuf(req, sel->val, sel->buf_list);