776 lines · 19.3 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0#include <linux/kernel.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/file.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/namei.h>#include <linux/poll.h>#include <linux/uio.h>#include <linux/vmalloc.h>#include <linux/io_uring.h> #include <uapi/linux/io_uring.h> #include "io_uring.h"#include "opdef.h"#include "kbuf.h"#include "memmap.h" /* BIDs are addressed by a 16-bit field in a CQE */#define MAX_BIDS_PER_BGID (1 << 16) /* Mapped buffer ring, return io_uring_buf from head */#define io_ring_head_to_buf(br, head, mask)	(&(br)->bufs[(head) & (mask)]) struct io_provide_buf {	struct file			*file;	__u64				addr;	__u32				len;	__u32				bgid;	__u32				nbufs;	__u16				bid;}; static bool io_kbuf_inc_commit(struct io_buffer_list *bl, int len){	/* No data consumed, return false early to avoid consuming the buffer */	if (!len)		return false; 	while (len) {		struct io_uring_buf *buf;		u32 buf_len, this_len; 		buf = io_ring_head_to_buf(bl->buf_ring, bl->head, bl->mask);		buf_len = READ_ONCE(buf->len);		this_len = min_t(u32, len, buf_len);		buf_len -= this_len;		/* Stop looping for invalid buffer length of 0 */		if (buf_len > bl->min_left_sub_one || !this_len) {			WRITE_ONCE(buf->addr, READ_ONCE(buf->addr) + this_len);			WRITE_ONCE(buf->len, buf_len);			return false;		}		WRITE_ONCE(buf->len, 0);		bl->head++;		len -= this_len;	}	return true;} bool io_kbuf_commit(struct io_kiocb *req,		    struct io_buffer_list *bl, int len, int nr){	if (unlikely(!(req->flags & REQ_F_BUFFERS_COMMIT)))		return true; 	req->flags &= ~REQ_F_BUFFERS_COMMIT; 	if (unlikely(len < 0))		return true;	if (bl->flags & IOBL_INC)		return io_kbuf_inc_commit(bl, len);	bl->head += nr;	return true;} static inline struct io_buffer_list *io_buffer_get_list(struct io_ring_ctx *ctx,							unsigned int bgid){	lockdep_assert_held(&ctx->uring_lock); 	return xa_load(&ctx->io_bl_xa, bgid);} static int io_buffer_add_list(struct io_ring_ctx *ctx,			      struct io_buffer_list *bl, unsigned int bgid){	/*	 * Store buffer group ID and finally mark the list as visible.	 * The normal lookup doesn't care about the visibility as we're	 * always under the ->uring_lock, but lookups from mmap do.	 */	bl->bgid = bgid;	guard(mutex)(&ctx->mmap_lock);	return xa_err(xa_store(&ctx->io_bl_xa, bgid, bl, GFP_KERNEL));} void io_kbuf_drop_legacy(struct io_kiocb *req){	if (WARN_ON_ONCE(!(req->flags & REQ_F_BUFFER_SELECTED)))		return;	req->flags &= ~REQ_F_BUFFER_SELECTED;	kfree(req->kbuf);	req->kbuf = NULL;} bool io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags){	struct io_ring_ctx *ctx = req->ctx;	struct io_buffer_list *bl;	struct io_buffer *buf; 	io_ring_submit_lock(ctx, issue_flags); 	buf = req->kbuf;	bl = io_buffer_get_list(ctx, buf->bgid);	/*	 * If the buffer list was upgraded to a ring-based one, or removed,	 * while the request was in-flight in io-wq, drop it.	 */	if (bl && !(bl->flags & IOBL_BUF_RING)) {		list_add(&buf->list, &bl->buf_list);		bl->nbufs++;	} else {		kfree(buf);	}	req->flags &= ~REQ_F_BUFFER_SELECTED;	req->kbuf = NULL; 	io_ring_submit_unlock(ctx, issue_flags);	return true;} static void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,					      struct io_buffer_list *bl){	if (!list_empty(&bl->buf_list)) {		struct io_buffer *kbuf; 		kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);		list_del(&kbuf->list);		bl->nbufs--;		if (*len == 0 || *len > kbuf->len)			*len = kbuf->len;		if (list_empty(&bl->buf_list))			req->flags |= REQ_F_BL_EMPTY;		req->flags |= REQ_F_BUFFER_SELECTED;		req->kbuf = kbuf;		req->buf_index = kbuf->bid;		return u64_to_user_ptr(kbuf->addr);	}	return NULL;} static int io_provided_buffers_select(struct io_kiocb *req, size_t *len,				      struct io_buffer_list *bl,				      struct iovec *iov){	void __user *buf; 	buf = io_provided_buffer_select(req, len, bl);	if (unlikely(!buf))		return -ENOBUFS; 	iov[0].iov_base = buf;	iov[0].iov_len = *len;	return 1;} static bool io_should_commit(struct io_kiocb *req, unsigned int issue_flags){	/*	* If we came in unlocked, we have no choice but to consume the	* buffer here, otherwise nothing ensures that the buffer won't	* get used by others. This does mean it'll be pinned until the	* IO completes, coming in unlocked means we're being called from	* io-wq context and there may be further retries in async hybrid	* mode. For the locked case, the caller must call commit when	* the transfer completes (or if we get -EAGAIN and must poll of	* retry).	*/	if (issue_flags & IO_URING_F_UNLOCKED)		return true; 	/* uring_cmd commits kbuf upfront, no need to auto-commit */	if (!io_file_can_poll(req) && !io_is_uring_cmd(req))		return true;	return false;} static struct io_br_sel io_ring_buffer_select(struct io_kiocb *req, size_t *len,					      struct io_buffer_list *bl,					      unsigned int issue_flags){	struct io_uring_buf_ring *br = bl->buf_ring;	__u16 tail, head = bl->head;	struct io_br_sel sel = { };	struct io_uring_buf *buf;	u32 buf_len; 	tail = smp_load_acquire(&br->tail);	if (unlikely(tail == head))		return sel; 	if (head + 1 == tail)		req->flags |= REQ_F_BL_EMPTY; 	buf = io_ring_head_to_buf(br, head, bl->mask);	buf_len = READ_ONCE(buf->len);	if (*len == 0 || *len > buf_len)		*len = buf_len;	sel.addr = u64_to_user_ptr(READ_ONCE(buf->addr));	if (unlikely(!access_ok(sel.addr, *len))) {		sel.addr = NULL;		return sel;	}	req->flags |= REQ_F_BUFFER_RING | REQ_F_BUFFERS_COMMIT;	req->buf_index = READ_ONCE(buf->bid);	sel.buf_list = bl; 	if (io_should_commit(req, issue_flags)) {		if (!io_kbuf_commit(req, sel.buf_list, *len, 1))			req->flags |= REQ_F_BUF_MORE;		sel.buf_list = NULL;	}	return sel;} struct io_br_sel io_buffer_select(struct io_kiocb *req, size_t *len,				  unsigned buf_group, unsigned int issue_flags){	struct io_ring_ctx *ctx = req->ctx;	struct io_br_sel sel = { };	struct io_buffer_list *bl; 	io_ring_submit_lock(ctx, issue_flags); 	bl = io_buffer_get_list(ctx, buf_group);	if (likely(bl)) {		if (bl->flags & IOBL_BUF_RING)			sel = io_ring_buffer_select(req, len, bl, issue_flags);		else			sel.addr = io_provided_buffer_select(req, len, bl);	}	io_ring_submit_unlock(ctx, issue_flags);	return sel;} /* cap it at a reasonable 256, will be one page even for 4K */#define PEEK_MAX_IMPORT		256 static int io_ring_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,				struct io_buffer_list *bl){	struct io_uring_buf_ring *br = bl->buf_ring;	struct iovec *org_iovs = arg->iovs;	struct iovec *iov = arg->iovs;	int nr_iovs = arg->nr_iovs;	__u16 nr_avail, tail, head;	struct io_uring_buf *buf; 	tail = smp_load_acquire(&br->tail);	head = bl->head;	nr_avail = min_t(__u16, tail - head, UIO_MAXIOV);	if (unlikely(!nr_avail))		return -ENOBUFS; 	/* MAX_RW_COUNT is the universal Linux per-call IO maximum */	arg->max_len = min_t(size_t, arg->max_len, MAX_RW_COUNT); 	buf = io_ring_head_to_buf(br, head, bl->mask);	if (arg->max_len) {		u32 len = READ_ONCE(buf->len);		size_t needed; 		if (unlikely(!len))			return -ENOBUFS;		needed = (arg->max_len + len - 1) / len;		needed = min_not_zero(needed, (size_t) PEEK_MAX_IMPORT);		if (nr_avail > needed)			nr_avail = needed;	} 	/*	 * only alloc a bigger array if we know we have data to map, eg not	 * a speculative peek operation.	 */	if (arg->mode & KBUF_MODE_EXPAND && nr_avail > nr_iovs && arg->max_len) {		iov = kmalloc_objs(struct iovec, nr_avail);		if (unlikely(!iov))			return -ENOMEM;		arg->iovs = iov;		nr_iovs = nr_avail;	} else if (nr_avail < nr_iovs) {		nr_iovs = nr_avail;	} 	/* set it to max, if not set, so we can use it unconditionally */	if (!arg->max_len)		arg->max_len = MAX_RW_COUNT; 	req->buf_index = READ_ONCE(buf->bid);	do {		u32 len = READ_ONCE(buf->len); 		/* truncate end piece, if needed, for non partial buffers */		if (len > arg->max_len) {			len = arg->max_len;			if (!(bl->flags & IOBL_INC)) {				arg->partial_map = 1;				if (iov != arg->iovs)					break;			}		} 		iov->iov_base = u64_to_user_ptr(READ_ONCE(buf->addr));		iov->iov_len = len;		if (unlikely(!access_ok(iov->iov_base, len))) {			if (arg->iovs != org_iovs)				kfree(arg->iovs);			return -EFAULT;		}		iov++; 		arg->out_len += len;		arg->max_len -= len;		if (!arg->max_len)			break; 		buf = io_ring_head_to_buf(br, ++head, bl->mask);	} while (--nr_iovs); 	if (arg->iovs != org_iovs && (arg->mode & KBUF_MODE_FREE))		kfree(org_iovs); 	if (head == tail)		req->flags |= REQ_F_BL_EMPTY; 	req->flags |= REQ_F_BUFFER_RING;	return iov - arg->iovs;} int io_buffers_select(struct io_kiocb *req, struct buf_sel_arg *arg,		      struct io_br_sel *sel, unsigned int issue_flags){	struct io_ring_ctx *ctx = req->ctx;	int ret = -ENOENT; 	io_ring_submit_lock(ctx, issue_flags);	sel->buf_list = io_buffer_get_list(ctx, arg->buf_group);	if (unlikely(!sel->buf_list))		goto out_unlock; 	if (sel->buf_list->flags & IOBL_BUF_RING) {		ret = io_ring_buffers_peek(req, arg, sel->buf_list);		/*		 * Don't recycle these buffers if we need to go through poll.		 * Nobody else can use them anyway, and holding on to provided		 * buffers for a send/write operation would happen on the app		 * side anyway with normal buffers. Besides, we already		 * committed them, they cannot be put back in the queue.		 */		if (ret > 0) {			req->flags |= REQ_F_BUFFERS_COMMIT | REQ_F_BL_NO_RECYCLE;			if (!io_kbuf_commit(req, sel->buf_list, arg->out_len, ret))				req->flags |= REQ_F_BUF_MORE;		}	} else {		ret = io_provided_buffers_select(req, &arg->out_len, sel->buf_list, arg->iovs);	}out_unlock:	if (issue_flags & IO_URING_F_UNLOCKED) {		sel->buf_list = NULL;		mutex_unlock(&ctx->uring_lock);	}	return ret;} int io_buffers_peek(struct io_kiocb *req, struct buf_sel_arg *arg,		    struct io_br_sel *sel){	struct io_ring_ctx *ctx = req->ctx;	struct io_buffer_list *bl;	int ret; 	lockdep_assert_held(&ctx->uring_lock); 	bl = io_buffer_get_list(ctx, arg->buf_group);	if (unlikely(!bl))		return -ENOENT; 	if (bl->flags & IOBL_BUF_RING) {		ret = io_ring_buffers_peek(req, arg, bl);		if (ret > 0)			req->flags |= REQ_F_BUFFERS_COMMIT;		sel->buf_list = bl;		return ret;	} 	/* don't support multiple buffer selections for legacy */	sel->buf_list = NULL;	return io_provided_buffers_select(req, &arg->max_len, bl, arg->iovs);} static inline bool __io_put_kbuf_ring(struct io_kiocb *req,				      struct io_buffer_list *bl, int len, int nr){	bool ret = true; 	if (bl)		ret = io_kbuf_commit(req, bl, len, nr);	if (ret && (req->flags & REQ_F_BUF_MORE))		ret = false; 	req->flags &= ~(REQ_F_BUFFER_RING | REQ_F_BUF_MORE);	return ret;} unsigned int __io_put_kbufs(struct io_kiocb *req, struct io_buffer_list *bl,			    int len, int nbufs){	unsigned int ret; 	ret = IORING_CQE_F_BUFFER | (req->buf_index << IORING_CQE_BUFFER_SHIFT); 	if (unlikely(!(req->flags & REQ_F_BUFFER_RING))) {		io_kbuf_drop_legacy(req);		return ret;	} 	if (!__io_put_kbuf_ring(req, bl, len, nbufs))		ret |= IORING_CQE_F_BUF_MORE;	return ret;} static int io_remove_buffers_legacy(struct io_ring_ctx *ctx,				    struct io_buffer_list *bl,				    unsigned long nbufs){	unsigned long i = 0;	struct io_buffer *nxt; 	/* protects io_buffers_cache */	lockdep_assert_held(&ctx->uring_lock);	WARN_ON_ONCE(bl->flags & IOBL_BUF_RING); 	for (i = 0; i < nbufs && !list_empty(&bl->buf_list); i++) {		nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);		list_del(&nxt->list);		bl->nbufs--;		kfree(nxt);		cond_resched();	}	return i;} static void io_put_bl(struct io_ring_ctx *ctx, struct io_buffer_list *bl){	if (bl->flags & IOBL_BUF_RING)		io_free_region(ctx->user, &bl->region);	else		io_remove_buffers_legacy(ctx, bl, -1U); 	kfree(bl);} void io_destroy_buffers(struct io_ring_ctx *ctx){	struct io_buffer_list *bl; 	while (1) {		unsigned long index = 0; 		scoped_guard(mutex, &ctx->mmap_lock) {			bl = xa_find(&ctx->io_bl_xa, &index, ULONG_MAX, XA_PRESENT);			if (bl)				xa_erase(&ctx->io_bl_xa, bl->bgid);		}		if (!bl)			break;		io_put_bl(ctx, bl);	}} static void io_destroy_bl(struct io_ring_ctx *ctx, struct io_buffer_list *bl){	scoped_guard(mutex, &ctx->mmap_lock)		WARN_ON_ONCE(xa_erase(&ctx->io_bl_xa, bl->bgid) != bl);	io_put_bl(ctx, bl);} int io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe){	struct io_provide_buf *p = io_kiocb_to_cmd(req, struct io_provide_buf);	u64 tmp; 	if (sqe->rw_flags || sqe->addr || sqe->len || sqe->off ||	    sqe->splice_fd_in)

Lines 1–500 of 776.