162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/kernel.h>
362306a36Sopenharmony_ci#include <linux/errno.h>
462306a36Sopenharmony_ci#include <linux/fs.h>
562306a36Sopenharmony_ci#include <linux/file.h>
662306a36Sopenharmony_ci#include <linux/mm.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci#include <linux/namei.h>
962306a36Sopenharmony_ci#include <linux/poll.h>
1062306a36Sopenharmony_ci#include <linux/io_uring.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <uapi/linux/io_uring.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include "io_uring.h"
1562306a36Sopenharmony_ci#include "opdef.h"
1662306a36Sopenharmony_ci#include "kbuf.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#define IO_BUFFER_LIST_BUF_PER_PAGE (PAGE_SIZE / sizeof(struct io_uring_buf))
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#define BGID_ARRAY	64
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/* BIDs are addressed by a 16-bit field in a CQE */
2362306a36Sopenharmony_ci#define MAX_BIDS_PER_BGID (1 << 16)
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_cistruct io_provide_buf {
2662306a36Sopenharmony_ci	struct file			*file;
2762306a36Sopenharmony_ci	__u64				addr;
2862306a36Sopenharmony_ci	__u32				len;
2962306a36Sopenharmony_ci	__u32				bgid;
3062306a36Sopenharmony_ci	__u32				nbufs;
3162306a36Sopenharmony_ci	__u16				bid;
3262306a36Sopenharmony_ci};
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic struct io_buffer_list *__io_buffer_get_list(struct io_ring_ctx *ctx,
3562306a36Sopenharmony_ci						   struct io_buffer_list *bl,
3662306a36Sopenharmony_ci						   unsigned int bgid)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	if (bl && bgid < BGID_ARRAY)
3962306a36Sopenharmony_ci		return &bl[bgid];
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	return xa_load(&ctx->io_bl_xa, bgid);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistruct io_buf_free {
4562306a36Sopenharmony_ci	struct hlist_node		list;
4662306a36Sopenharmony_ci	void				*mem;
4762306a36Sopenharmony_ci	size_t				size;
4862306a36Sopenharmony_ci	int				inuse;
4962306a36Sopenharmony_ci};
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_cistatic inline struct io_buffer_list *io_buffer_get_list(struct io_ring_ctx *ctx,
5262306a36Sopenharmony_ci							unsigned int bgid)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	lockdep_assert_held(&ctx->uring_lock);
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	return __io_buffer_get_list(ctx, ctx->io_bl, bgid);
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic int io_buffer_add_list(struct io_ring_ctx *ctx,
6062306a36Sopenharmony_ci			      struct io_buffer_list *bl, unsigned int bgid)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * Store buffer group ID and finally mark the list as visible.
6462306a36Sopenharmony_ci	 * The normal lookup doesn't care about the visibility as we're
6562306a36Sopenharmony_ci	 * always under the ->uring_lock, but the RCU lookup from mmap does.
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	bl->bgid = bgid;
6862306a36Sopenharmony_ci	smp_store_release(&bl->is_ready, 1);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (bgid < BGID_ARRAY)
7162306a36Sopenharmony_ci		return 0;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	return xa_err(xa_store(&ctx->io_bl_xa, bgid, bl, GFP_KERNEL));
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_civoid io_kbuf_recycle_legacy(struct io_kiocb *req, unsigned issue_flags)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct io_ring_ctx *ctx = req->ctx;
7962306a36Sopenharmony_ci	struct io_buffer_list *bl;
8062306a36Sopenharmony_ci	struct io_buffer *buf;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	/*
8362306a36Sopenharmony_ci	 * For legacy provided buffer mode, don't recycle if we already did
8462306a36Sopenharmony_ci	 * IO to this buffer. For ring-mapped provided buffer mode, we should
8562306a36Sopenharmony_ci	 * increment ring->head to explicitly monopolize the buffer to avoid
8662306a36Sopenharmony_ci	 * multiple use.
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	if (req->flags & REQ_F_PARTIAL_IO)
8962306a36Sopenharmony_ci		return;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	io_ring_submit_lock(ctx, issue_flags);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	buf = req->kbuf;
9462306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, buf->bgid);
9562306a36Sopenharmony_ci	list_add(&buf->list, &bl->buf_list);
9662306a36Sopenharmony_ci	req->flags &= ~REQ_F_BUFFER_SELECTED;
9762306a36Sopenharmony_ci	req->buf_index = buf->bgid;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	io_ring_submit_unlock(ctx, issue_flags);
10062306a36Sopenharmony_ci	return;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ciunsigned int __io_put_kbuf(struct io_kiocb *req, unsigned issue_flags)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	unsigned int cflags;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	/*
10862306a36Sopenharmony_ci	 * We can add this buffer back to two lists:
10962306a36Sopenharmony_ci	 *
11062306a36Sopenharmony_ci	 * 1) The io_buffers_cache list. This one is protected by the
11162306a36Sopenharmony_ci	 *    ctx->uring_lock. If we already hold this lock, add back to this
11262306a36Sopenharmony_ci	 *    list as we can grab it from issue as well.
11362306a36Sopenharmony_ci	 * 2) The io_buffers_comp list. This one is protected by the
11462306a36Sopenharmony_ci	 *    ctx->completion_lock.
11562306a36Sopenharmony_ci	 *
11662306a36Sopenharmony_ci	 * We migrate buffers from the comp_list to the issue cache list
11762306a36Sopenharmony_ci	 * when we need one.
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	if (req->flags & REQ_F_BUFFER_RING) {
12062306a36Sopenharmony_ci		/* no buffers to recycle for this case */
12162306a36Sopenharmony_ci		cflags = __io_put_kbuf_list(req, NULL);
12262306a36Sopenharmony_ci	} else if (issue_flags & IO_URING_F_UNLOCKED) {
12362306a36Sopenharmony_ci		struct io_ring_ctx *ctx = req->ctx;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		spin_lock(&ctx->completion_lock);
12662306a36Sopenharmony_ci		cflags = __io_put_kbuf_list(req, &ctx->io_buffers_comp);
12762306a36Sopenharmony_ci		spin_unlock(&ctx->completion_lock);
12862306a36Sopenharmony_ci	} else {
12962306a36Sopenharmony_ci		lockdep_assert_held(&req->ctx->uring_lock);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci		cflags = __io_put_kbuf_list(req, &req->ctx->io_buffers_cache);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci	return cflags;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic void __user *io_provided_buffer_select(struct io_kiocb *req, size_t *len,
13762306a36Sopenharmony_ci					      struct io_buffer_list *bl)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	if (!list_empty(&bl->buf_list)) {
14062306a36Sopenharmony_ci		struct io_buffer *kbuf;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		kbuf = list_first_entry(&bl->buf_list, struct io_buffer, list);
14362306a36Sopenharmony_ci		list_del(&kbuf->list);
14462306a36Sopenharmony_ci		if (*len == 0 || *len > kbuf->len)
14562306a36Sopenharmony_ci			*len = kbuf->len;
14662306a36Sopenharmony_ci		req->flags |= REQ_F_BUFFER_SELECTED;
14762306a36Sopenharmony_ci		req->kbuf = kbuf;
14862306a36Sopenharmony_ci		req->buf_index = kbuf->bid;
14962306a36Sopenharmony_ci		return u64_to_user_ptr(kbuf->addr);
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci	return NULL;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_cistatic void __user *io_ring_buffer_select(struct io_kiocb *req, size_t *len,
15562306a36Sopenharmony_ci					  struct io_buffer_list *bl,
15662306a36Sopenharmony_ci					  unsigned int issue_flags)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct io_uring_buf_ring *br = bl->buf_ring;
15962306a36Sopenharmony_ci	struct io_uring_buf *buf;
16062306a36Sopenharmony_ci	__u16 head = bl->head;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (unlikely(smp_load_acquire(&br->tail) == head))
16362306a36Sopenharmony_ci		return NULL;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	head &= bl->mask;
16662306a36Sopenharmony_ci	/* mmaped buffers are always contig */
16762306a36Sopenharmony_ci	if (bl->is_mmap || head < IO_BUFFER_LIST_BUF_PER_PAGE) {
16862306a36Sopenharmony_ci		buf = &br->bufs[head];
16962306a36Sopenharmony_ci	} else {
17062306a36Sopenharmony_ci		int off = head & (IO_BUFFER_LIST_BUF_PER_PAGE - 1);
17162306a36Sopenharmony_ci		int index = head / IO_BUFFER_LIST_BUF_PER_PAGE;
17262306a36Sopenharmony_ci		buf = page_address(bl->buf_pages[index]);
17362306a36Sopenharmony_ci		buf += off;
17462306a36Sopenharmony_ci	}
17562306a36Sopenharmony_ci	if (*len == 0 || *len > buf->len)
17662306a36Sopenharmony_ci		*len = buf->len;
17762306a36Sopenharmony_ci	req->flags |= REQ_F_BUFFER_RING;
17862306a36Sopenharmony_ci	req->buf_list = bl;
17962306a36Sopenharmony_ci	req->buf_index = buf->bid;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (issue_flags & IO_URING_F_UNLOCKED || !file_can_poll(req->file)) {
18262306a36Sopenharmony_ci		/*
18362306a36Sopenharmony_ci		 * If we came in unlocked, we have no choice but to consume the
18462306a36Sopenharmony_ci		 * buffer here, otherwise nothing ensures that the buffer won't
18562306a36Sopenharmony_ci		 * get used by others. This does mean it'll be pinned until the
18662306a36Sopenharmony_ci		 * IO completes, coming in unlocked means we're being called from
18762306a36Sopenharmony_ci		 * io-wq context and there may be further retries in async hybrid
18862306a36Sopenharmony_ci		 * mode. For the locked case, the caller must call commit when
18962306a36Sopenharmony_ci		 * the transfer completes (or if we get -EAGAIN and must poll of
19062306a36Sopenharmony_ci		 * retry).
19162306a36Sopenharmony_ci		 */
19262306a36Sopenharmony_ci		req->buf_list = NULL;
19362306a36Sopenharmony_ci		bl->head++;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	return u64_to_user_ptr(buf->addr);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_civoid __user *io_buffer_select(struct io_kiocb *req, size_t *len,
19962306a36Sopenharmony_ci			      unsigned int issue_flags)
20062306a36Sopenharmony_ci{
20162306a36Sopenharmony_ci	struct io_ring_ctx *ctx = req->ctx;
20262306a36Sopenharmony_ci	struct io_buffer_list *bl;
20362306a36Sopenharmony_ci	void __user *ret = NULL;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	io_ring_submit_lock(req->ctx, issue_flags);
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, req->buf_index);
20862306a36Sopenharmony_ci	if (likely(bl)) {
20962306a36Sopenharmony_ci		if (bl->is_mapped)
21062306a36Sopenharmony_ci			ret = io_ring_buffer_select(req, len, bl, issue_flags);
21162306a36Sopenharmony_ci		else
21262306a36Sopenharmony_ci			ret = io_provided_buffer_select(req, len, bl);
21362306a36Sopenharmony_ci	}
21462306a36Sopenharmony_ci	io_ring_submit_unlock(req->ctx, issue_flags);
21562306a36Sopenharmony_ci	return ret;
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_cistatic __cold int io_init_bl_list(struct io_ring_ctx *ctx)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct io_buffer_list *bl;
22162306a36Sopenharmony_ci	int i;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	bl = kcalloc(BGID_ARRAY, sizeof(struct io_buffer_list), GFP_KERNEL);
22462306a36Sopenharmony_ci	if (!bl)
22562306a36Sopenharmony_ci		return -ENOMEM;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	for (i = 0; i < BGID_ARRAY; i++) {
22862306a36Sopenharmony_ci		INIT_LIST_HEAD(&bl[i].buf_list);
22962306a36Sopenharmony_ci		bl[i].bgid = i;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	smp_store_release(&ctx->io_bl, bl);
23362306a36Sopenharmony_ci	return 0;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*
23762306a36Sopenharmony_ci * Mark the given mapped range as free for reuse
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void io_kbuf_mark_free(struct io_ring_ctx *ctx, struct io_buffer_list *bl)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct io_buf_free *ibf;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	hlist_for_each_entry(ibf, &ctx->io_buf_list, list) {
24462306a36Sopenharmony_ci		if (bl->buf_ring == ibf->mem) {
24562306a36Sopenharmony_ci			ibf->inuse = 0;
24662306a36Sopenharmony_ci			return;
24762306a36Sopenharmony_ci		}
24862306a36Sopenharmony_ci	}
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci	/* can't happen... */
25162306a36Sopenharmony_ci	WARN_ON_ONCE(1);
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int __io_remove_buffers(struct io_ring_ctx *ctx,
25562306a36Sopenharmony_ci			       struct io_buffer_list *bl, unsigned nbufs)
25662306a36Sopenharmony_ci{
25762306a36Sopenharmony_ci	unsigned i = 0;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/* shouldn't happen */
26062306a36Sopenharmony_ci	if (!nbufs)
26162306a36Sopenharmony_ci		return 0;
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	if (bl->is_mapped) {
26462306a36Sopenharmony_ci		i = bl->buf_ring->tail - bl->head;
26562306a36Sopenharmony_ci		if (bl->is_mmap) {
26662306a36Sopenharmony_ci			/*
26762306a36Sopenharmony_ci			 * io_kbuf_list_free() will free the page(s) at
26862306a36Sopenharmony_ci			 * ->release() time.
26962306a36Sopenharmony_ci			 */
27062306a36Sopenharmony_ci			io_kbuf_mark_free(ctx, bl);
27162306a36Sopenharmony_ci			bl->buf_ring = NULL;
27262306a36Sopenharmony_ci			bl->is_mmap = 0;
27362306a36Sopenharmony_ci		} else if (bl->buf_nr_pages) {
27462306a36Sopenharmony_ci			int j;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci			for (j = 0; j < bl->buf_nr_pages; j++)
27762306a36Sopenharmony_ci				unpin_user_page(bl->buf_pages[j]);
27862306a36Sopenharmony_ci			kvfree(bl->buf_pages);
27962306a36Sopenharmony_ci			bl->buf_pages = NULL;
28062306a36Sopenharmony_ci			bl->buf_nr_pages = 0;
28162306a36Sopenharmony_ci		}
28262306a36Sopenharmony_ci		/* make sure it's seen as empty */
28362306a36Sopenharmony_ci		INIT_LIST_HEAD(&bl->buf_list);
28462306a36Sopenharmony_ci		bl->is_mapped = 0;
28562306a36Sopenharmony_ci		return i;
28662306a36Sopenharmony_ci	}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	/* protects io_buffers_cache */
28962306a36Sopenharmony_ci	lockdep_assert_held(&ctx->uring_lock);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	while (!list_empty(&bl->buf_list)) {
29262306a36Sopenharmony_ci		struct io_buffer *nxt;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		nxt = list_first_entry(&bl->buf_list, struct io_buffer, list);
29562306a36Sopenharmony_ci		list_move(&nxt->list, &ctx->io_buffers_cache);
29662306a36Sopenharmony_ci		if (++i == nbufs)
29762306a36Sopenharmony_ci			return i;
29862306a36Sopenharmony_ci		cond_resched();
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	return i;
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_civoid io_destroy_buffers(struct io_ring_ctx *ctx)
30562306a36Sopenharmony_ci{
30662306a36Sopenharmony_ci	struct io_buffer_list *bl;
30762306a36Sopenharmony_ci	unsigned long index;
30862306a36Sopenharmony_ci	int i;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	for (i = 0; i < BGID_ARRAY; i++) {
31162306a36Sopenharmony_ci		if (!ctx->io_bl)
31262306a36Sopenharmony_ci			break;
31362306a36Sopenharmony_ci		__io_remove_buffers(ctx, &ctx->io_bl[i], -1U);
31462306a36Sopenharmony_ci	}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	xa_for_each(&ctx->io_bl_xa, index, bl) {
31762306a36Sopenharmony_ci		xa_erase(&ctx->io_bl_xa, bl->bgid);
31862306a36Sopenharmony_ci		__io_remove_buffers(ctx, bl, -1U);
31962306a36Sopenharmony_ci		kfree_rcu(bl, rcu);
32062306a36Sopenharmony_ci	}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	while (!list_empty(&ctx->io_buffers_pages)) {
32362306a36Sopenharmony_ci		struct page *page;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci		page = list_first_entry(&ctx->io_buffers_pages, struct page, lru);
32662306a36Sopenharmony_ci		list_del_init(&page->lru);
32762306a36Sopenharmony_ci		__free_page(page);
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ciint io_remove_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
33262306a36Sopenharmony_ci{
33362306a36Sopenharmony_ci	struct io_provide_buf *p = io_kiocb_to_cmd(req, struct io_provide_buf);
33462306a36Sopenharmony_ci	u64 tmp;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (sqe->rw_flags || sqe->addr || sqe->len || sqe->off ||
33762306a36Sopenharmony_ci	    sqe->splice_fd_in)
33862306a36Sopenharmony_ci		return -EINVAL;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	tmp = READ_ONCE(sqe->fd);
34162306a36Sopenharmony_ci	if (!tmp || tmp > MAX_BIDS_PER_BGID)
34262306a36Sopenharmony_ci		return -EINVAL;
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	memset(p, 0, sizeof(*p));
34562306a36Sopenharmony_ci	p->nbufs = tmp;
34662306a36Sopenharmony_ci	p->bgid = READ_ONCE(sqe->buf_group);
34762306a36Sopenharmony_ci	return 0;
34862306a36Sopenharmony_ci}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ciint io_remove_buffers(struct io_kiocb *req, unsigned int issue_flags)
35162306a36Sopenharmony_ci{
35262306a36Sopenharmony_ci	struct io_provide_buf *p = io_kiocb_to_cmd(req, struct io_provide_buf);
35362306a36Sopenharmony_ci	struct io_ring_ctx *ctx = req->ctx;
35462306a36Sopenharmony_ci	struct io_buffer_list *bl;
35562306a36Sopenharmony_ci	int ret = 0;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	io_ring_submit_lock(ctx, issue_flags);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	ret = -ENOENT;
36062306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, p->bgid);
36162306a36Sopenharmony_ci	if (bl) {
36262306a36Sopenharmony_ci		ret = -EINVAL;
36362306a36Sopenharmony_ci		/* can't use provide/remove buffers command on mapped buffers */
36462306a36Sopenharmony_ci		if (!bl->is_mapped)
36562306a36Sopenharmony_ci			ret = __io_remove_buffers(ctx, bl, p->nbufs);
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci	io_ring_submit_unlock(ctx, issue_flags);
36862306a36Sopenharmony_ci	if (ret < 0)
36962306a36Sopenharmony_ci		req_set_fail(req);
37062306a36Sopenharmony_ci	io_req_set_res(req, ret, 0);
37162306a36Sopenharmony_ci	return IOU_OK;
37262306a36Sopenharmony_ci}
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ciint io_provide_buffers_prep(struct io_kiocb *req, const struct io_uring_sqe *sqe)
37562306a36Sopenharmony_ci{
37662306a36Sopenharmony_ci	unsigned long size, tmp_check;
37762306a36Sopenharmony_ci	struct io_provide_buf *p = io_kiocb_to_cmd(req, struct io_provide_buf);
37862306a36Sopenharmony_ci	u64 tmp;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	if (sqe->rw_flags || sqe->splice_fd_in)
38162306a36Sopenharmony_ci		return -EINVAL;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	tmp = READ_ONCE(sqe->fd);
38462306a36Sopenharmony_ci	if (!tmp || tmp > MAX_BIDS_PER_BGID)
38562306a36Sopenharmony_ci		return -E2BIG;
38662306a36Sopenharmony_ci	p->nbufs = tmp;
38762306a36Sopenharmony_ci	p->addr = READ_ONCE(sqe->addr);
38862306a36Sopenharmony_ci	p->len = READ_ONCE(sqe->len);
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci	if (check_mul_overflow((unsigned long)p->len, (unsigned long)p->nbufs,
39162306a36Sopenharmony_ci				&size))
39262306a36Sopenharmony_ci		return -EOVERFLOW;
39362306a36Sopenharmony_ci	if (check_add_overflow((unsigned long)p->addr, size, &tmp_check))
39462306a36Sopenharmony_ci		return -EOVERFLOW;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	size = (unsigned long)p->len * p->nbufs;
39762306a36Sopenharmony_ci	if (!access_ok(u64_to_user_ptr(p->addr), size))
39862306a36Sopenharmony_ci		return -EFAULT;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	p->bgid = READ_ONCE(sqe->buf_group);
40162306a36Sopenharmony_ci	tmp = READ_ONCE(sqe->off);
40262306a36Sopenharmony_ci	if (tmp > USHRT_MAX)
40362306a36Sopenharmony_ci		return -E2BIG;
40462306a36Sopenharmony_ci	if (tmp + p->nbufs > MAX_BIDS_PER_BGID)
40562306a36Sopenharmony_ci		return -EINVAL;
40662306a36Sopenharmony_ci	p->bid = tmp;
40762306a36Sopenharmony_ci	return 0;
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_cistatic int io_refill_buffer_cache(struct io_ring_ctx *ctx)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct io_buffer *buf;
41362306a36Sopenharmony_ci	struct page *page;
41462306a36Sopenharmony_ci	int bufs_in_page;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	/*
41762306a36Sopenharmony_ci	 * Completions that don't happen inline (eg not under uring_lock) will
41862306a36Sopenharmony_ci	 * add to ->io_buffers_comp. If we don't have any free buffers, check
41962306a36Sopenharmony_ci	 * the completion list and splice those entries first.
42062306a36Sopenharmony_ci	 */
42162306a36Sopenharmony_ci	if (!list_empty_careful(&ctx->io_buffers_comp)) {
42262306a36Sopenharmony_ci		spin_lock(&ctx->completion_lock);
42362306a36Sopenharmony_ci		if (!list_empty(&ctx->io_buffers_comp)) {
42462306a36Sopenharmony_ci			list_splice_init(&ctx->io_buffers_comp,
42562306a36Sopenharmony_ci						&ctx->io_buffers_cache);
42662306a36Sopenharmony_ci			spin_unlock(&ctx->completion_lock);
42762306a36Sopenharmony_ci			return 0;
42862306a36Sopenharmony_ci		}
42962306a36Sopenharmony_ci		spin_unlock(&ctx->completion_lock);
43062306a36Sopenharmony_ci	}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	/*
43362306a36Sopenharmony_ci	 * No free buffers and no completion entries either. Allocate a new
43462306a36Sopenharmony_ci	 * page worth of buffer entries and add those to our freelist.
43562306a36Sopenharmony_ci	 */
43662306a36Sopenharmony_ci	page = alloc_page(GFP_KERNEL_ACCOUNT);
43762306a36Sopenharmony_ci	if (!page)
43862306a36Sopenharmony_ci		return -ENOMEM;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	list_add(&page->lru, &ctx->io_buffers_pages);
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	buf = page_address(page);
44362306a36Sopenharmony_ci	bufs_in_page = PAGE_SIZE / sizeof(*buf);
44462306a36Sopenharmony_ci	while (bufs_in_page) {
44562306a36Sopenharmony_ci		list_add_tail(&buf->list, &ctx->io_buffers_cache);
44662306a36Sopenharmony_ci		buf++;
44762306a36Sopenharmony_ci		bufs_in_page--;
44862306a36Sopenharmony_ci	}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int io_add_buffers(struct io_ring_ctx *ctx, struct io_provide_buf *pbuf,
45462306a36Sopenharmony_ci			  struct io_buffer_list *bl)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	struct io_buffer *buf;
45762306a36Sopenharmony_ci	u64 addr = pbuf->addr;
45862306a36Sopenharmony_ci	int i, bid = pbuf->bid;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	for (i = 0; i < pbuf->nbufs; i++) {
46162306a36Sopenharmony_ci		if (list_empty(&ctx->io_buffers_cache) &&
46262306a36Sopenharmony_ci		    io_refill_buffer_cache(ctx))
46362306a36Sopenharmony_ci			break;
46462306a36Sopenharmony_ci		buf = list_first_entry(&ctx->io_buffers_cache, struct io_buffer,
46562306a36Sopenharmony_ci					list);
46662306a36Sopenharmony_ci		list_move_tail(&buf->list, &bl->buf_list);
46762306a36Sopenharmony_ci		buf->addr = addr;
46862306a36Sopenharmony_ci		buf->len = min_t(__u32, pbuf->len, MAX_RW_COUNT);
46962306a36Sopenharmony_ci		buf->bid = bid;
47062306a36Sopenharmony_ci		buf->bgid = pbuf->bgid;
47162306a36Sopenharmony_ci		addr += pbuf->len;
47262306a36Sopenharmony_ci		bid++;
47362306a36Sopenharmony_ci		cond_resched();
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	return i ? 0 : -ENOMEM;
47762306a36Sopenharmony_ci}
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ciint io_provide_buffers(struct io_kiocb *req, unsigned int issue_flags)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	struct io_provide_buf *p = io_kiocb_to_cmd(req, struct io_provide_buf);
48262306a36Sopenharmony_ci	struct io_ring_ctx *ctx = req->ctx;
48362306a36Sopenharmony_ci	struct io_buffer_list *bl;
48462306a36Sopenharmony_ci	int ret = 0;
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	io_ring_submit_lock(ctx, issue_flags);
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci	if (unlikely(p->bgid < BGID_ARRAY && !ctx->io_bl)) {
48962306a36Sopenharmony_ci		ret = io_init_bl_list(ctx);
49062306a36Sopenharmony_ci		if (ret)
49162306a36Sopenharmony_ci			goto err;
49262306a36Sopenharmony_ci	}
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, p->bgid);
49562306a36Sopenharmony_ci	if (unlikely(!bl)) {
49662306a36Sopenharmony_ci		bl = kzalloc(sizeof(*bl), GFP_KERNEL_ACCOUNT);
49762306a36Sopenharmony_ci		if (!bl) {
49862306a36Sopenharmony_ci			ret = -ENOMEM;
49962306a36Sopenharmony_ci			goto err;
50062306a36Sopenharmony_ci		}
50162306a36Sopenharmony_ci		INIT_LIST_HEAD(&bl->buf_list);
50262306a36Sopenharmony_ci		ret = io_buffer_add_list(ctx, bl, p->bgid);
50362306a36Sopenharmony_ci		if (ret) {
50462306a36Sopenharmony_ci			/*
50562306a36Sopenharmony_ci			 * Doesn't need rcu free as it was never visible, but
50662306a36Sopenharmony_ci			 * let's keep it consistent throughout. Also can't
50762306a36Sopenharmony_ci			 * be a lower indexed array group, as adding one
50862306a36Sopenharmony_ci			 * where lookup failed cannot happen.
50962306a36Sopenharmony_ci			 */
51062306a36Sopenharmony_ci			if (p->bgid >= BGID_ARRAY)
51162306a36Sopenharmony_ci				kfree_rcu(bl, rcu);
51262306a36Sopenharmony_ci			else
51362306a36Sopenharmony_ci				WARN_ON_ONCE(1);
51462306a36Sopenharmony_ci			goto err;
51562306a36Sopenharmony_ci		}
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci	/* can't add buffers via this command for a mapped buffer ring */
51862306a36Sopenharmony_ci	if (bl->is_mapped) {
51962306a36Sopenharmony_ci		ret = -EINVAL;
52062306a36Sopenharmony_ci		goto err;
52162306a36Sopenharmony_ci	}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci	ret = io_add_buffers(ctx, p, bl);
52462306a36Sopenharmony_cierr:
52562306a36Sopenharmony_ci	io_ring_submit_unlock(ctx, issue_flags);
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci	if (ret < 0)
52862306a36Sopenharmony_ci		req_set_fail(req);
52962306a36Sopenharmony_ci	io_req_set_res(req, ret, 0);
53062306a36Sopenharmony_ci	return IOU_OK;
53162306a36Sopenharmony_ci}
53262306a36Sopenharmony_ci
53362306a36Sopenharmony_cistatic int io_pin_pbuf_ring(struct io_uring_buf_reg *reg,
53462306a36Sopenharmony_ci			    struct io_buffer_list *bl)
53562306a36Sopenharmony_ci{
53662306a36Sopenharmony_ci	struct io_uring_buf_ring *br;
53762306a36Sopenharmony_ci	struct page **pages;
53862306a36Sopenharmony_ci	int i, nr_pages;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	pages = io_pin_pages(reg->ring_addr,
54162306a36Sopenharmony_ci			     flex_array_size(br, bufs, reg->ring_entries),
54262306a36Sopenharmony_ci			     &nr_pages);
54362306a36Sopenharmony_ci	if (IS_ERR(pages))
54462306a36Sopenharmony_ci		return PTR_ERR(pages);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/*
54762306a36Sopenharmony_ci	 * Apparently some 32-bit boxes (ARM) will return highmem pages,
54862306a36Sopenharmony_ci	 * which then need to be mapped. We could support that, but it'd
54962306a36Sopenharmony_ci	 * complicate the code and slowdown the common cases quite a bit.
55062306a36Sopenharmony_ci	 * So just error out, returning -EINVAL just like we did on kernels
55162306a36Sopenharmony_ci	 * that didn't support mapped buffer rings.
55262306a36Sopenharmony_ci	 */
55362306a36Sopenharmony_ci	for (i = 0; i < nr_pages; i++)
55462306a36Sopenharmony_ci		if (PageHighMem(pages[i]))
55562306a36Sopenharmony_ci			goto error_unpin;
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	br = page_address(pages[0]);
55862306a36Sopenharmony_ci#ifdef SHM_COLOUR
55962306a36Sopenharmony_ci	/*
56062306a36Sopenharmony_ci	 * On platforms that have specific aliasing requirements, SHM_COLOUR
56162306a36Sopenharmony_ci	 * is set and we must guarantee that the kernel and user side align
56262306a36Sopenharmony_ci	 * nicely. We cannot do that if IOU_PBUF_RING_MMAP isn't set and
56362306a36Sopenharmony_ci	 * the application mmap's the provided ring buffer. Fail the request
56462306a36Sopenharmony_ci	 * if we, by chance, don't end up with aligned addresses. The app
56562306a36Sopenharmony_ci	 * should use IOU_PBUF_RING_MMAP instead, and liburing will handle
56662306a36Sopenharmony_ci	 * this transparently.
56762306a36Sopenharmony_ci	 */
56862306a36Sopenharmony_ci	if ((reg->ring_addr | (unsigned long) br) & (SHM_COLOUR - 1))
56962306a36Sopenharmony_ci		goto error_unpin;
57062306a36Sopenharmony_ci#endif
57162306a36Sopenharmony_ci	bl->buf_pages = pages;
57262306a36Sopenharmony_ci	bl->buf_nr_pages = nr_pages;
57362306a36Sopenharmony_ci	bl->buf_ring = br;
57462306a36Sopenharmony_ci	bl->is_mapped = 1;
57562306a36Sopenharmony_ci	bl->is_mmap = 0;
57662306a36Sopenharmony_ci	return 0;
57762306a36Sopenharmony_cierror_unpin:
57862306a36Sopenharmony_ci	for (i = 0; i < nr_pages; i++)
57962306a36Sopenharmony_ci		unpin_user_page(pages[i]);
58062306a36Sopenharmony_ci	kvfree(pages);
58162306a36Sopenharmony_ci	return -EINVAL;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci/*
58562306a36Sopenharmony_ci * See if we have a suitable region that we can reuse, rather than allocate
58662306a36Sopenharmony_ci * both a new io_buf_free and mem region again. We leave it on the list as
58762306a36Sopenharmony_ci * even a reused entry will need freeing at ring release.
58862306a36Sopenharmony_ci */
58962306a36Sopenharmony_cistatic struct io_buf_free *io_lookup_buf_free_entry(struct io_ring_ctx *ctx,
59062306a36Sopenharmony_ci						    size_t ring_size)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct io_buf_free *ibf, *best = NULL;
59362306a36Sopenharmony_ci	size_t best_dist;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	hlist_for_each_entry(ibf, &ctx->io_buf_list, list) {
59662306a36Sopenharmony_ci		size_t dist;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci		if (ibf->inuse || ibf->size < ring_size)
59962306a36Sopenharmony_ci			continue;
60062306a36Sopenharmony_ci		dist = ibf->size - ring_size;
60162306a36Sopenharmony_ci		if (!best || dist < best_dist) {
60262306a36Sopenharmony_ci			best = ibf;
60362306a36Sopenharmony_ci			if (!dist)
60462306a36Sopenharmony_ci				break;
60562306a36Sopenharmony_ci			best_dist = dist;
60662306a36Sopenharmony_ci		}
60762306a36Sopenharmony_ci	}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	return best;
61062306a36Sopenharmony_ci}
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_cistatic int io_alloc_pbuf_ring(struct io_ring_ctx *ctx,
61362306a36Sopenharmony_ci			      struct io_uring_buf_reg *reg,
61462306a36Sopenharmony_ci			      struct io_buffer_list *bl)
61562306a36Sopenharmony_ci{
61662306a36Sopenharmony_ci	struct io_buf_free *ibf;
61762306a36Sopenharmony_ci	size_t ring_size;
61862306a36Sopenharmony_ci	void *ptr;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	ring_size = reg->ring_entries * sizeof(struct io_uring_buf_ring);
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	/* Reuse existing entry, if we can */
62362306a36Sopenharmony_ci	ibf = io_lookup_buf_free_entry(ctx, ring_size);
62462306a36Sopenharmony_ci	if (!ibf) {
62562306a36Sopenharmony_ci		ptr = io_mem_alloc(ring_size);
62662306a36Sopenharmony_ci		if (IS_ERR(ptr))
62762306a36Sopenharmony_ci			return PTR_ERR(ptr);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci		/* Allocate and store deferred free entry */
63062306a36Sopenharmony_ci		ibf = kmalloc(sizeof(*ibf), GFP_KERNEL_ACCOUNT);
63162306a36Sopenharmony_ci		if (!ibf) {
63262306a36Sopenharmony_ci			io_mem_free(ptr);
63362306a36Sopenharmony_ci			return -ENOMEM;
63462306a36Sopenharmony_ci		}
63562306a36Sopenharmony_ci		ibf->mem = ptr;
63662306a36Sopenharmony_ci		ibf->size = ring_size;
63762306a36Sopenharmony_ci		hlist_add_head(&ibf->list, &ctx->io_buf_list);
63862306a36Sopenharmony_ci	}
63962306a36Sopenharmony_ci	ibf->inuse = 1;
64062306a36Sopenharmony_ci	bl->buf_ring = ibf->mem;
64162306a36Sopenharmony_ci	bl->is_mapped = 1;
64262306a36Sopenharmony_ci	bl->is_mmap = 1;
64362306a36Sopenharmony_ci	return 0;
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ciint io_register_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
64762306a36Sopenharmony_ci{
64862306a36Sopenharmony_ci	struct io_uring_buf_reg reg;
64962306a36Sopenharmony_ci	struct io_buffer_list *bl, *free_bl = NULL;
65062306a36Sopenharmony_ci	int ret;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	lockdep_assert_held(&ctx->uring_lock);
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_ci	if (copy_from_user(&reg, arg, sizeof(reg)))
65562306a36Sopenharmony_ci		return -EFAULT;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	if (reg.resv[0] || reg.resv[1] || reg.resv[2])
65862306a36Sopenharmony_ci		return -EINVAL;
65962306a36Sopenharmony_ci	if (reg.flags & ~IOU_PBUF_RING_MMAP)
66062306a36Sopenharmony_ci		return -EINVAL;
66162306a36Sopenharmony_ci	if (!(reg.flags & IOU_PBUF_RING_MMAP)) {
66262306a36Sopenharmony_ci		if (!reg.ring_addr)
66362306a36Sopenharmony_ci			return -EFAULT;
66462306a36Sopenharmony_ci		if (reg.ring_addr & ~PAGE_MASK)
66562306a36Sopenharmony_ci			return -EINVAL;
66662306a36Sopenharmony_ci	} else {
66762306a36Sopenharmony_ci		if (reg.ring_addr)
66862306a36Sopenharmony_ci			return -EINVAL;
66962306a36Sopenharmony_ci	}
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (!is_power_of_2(reg.ring_entries))
67262306a36Sopenharmony_ci		return -EINVAL;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	/* cannot disambiguate full vs empty due to head/tail size */
67562306a36Sopenharmony_ci	if (reg.ring_entries >= 65536)
67662306a36Sopenharmony_ci		return -EINVAL;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	if (unlikely(reg.bgid < BGID_ARRAY && !ctx->io_bl)) {
67962306a36Sopenharmony_ci		int ret = io_init_bl_list(ctx);
68062306a36Sopenharmony_ci		if (ret)
68162306a36Sopenharmony_ci			return ret;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, reg.bgid);
68562306a36Sopenharmony_ci	if (bl) {
68662306a36Sopenharmony_ci		/* if mapped buffer ring OR classic exists, don't allow */
68762306a36Sopenharmony_ci		if (bl->is_mapped || !list_empty(&bl->buf_list))
68862306a36Sopenharmony_ci			return -EEXIST;
68962306a36Sopenharmony_ci	} else {
69062306a36Sopenharmony_ci		free_bl = bl = kzalloc(sizeof(*bl), GFP_KERNEL);
69162306a36Sopenharmony_ci		if (!bl)
69262306a36Sopenharmony_ci			return -ENOMEM;
69362306a36Sopenharmony_ci	}
69462306a36Sopenharmony_ci
69562306a36Sopenharmony_ci	if (!(reg.flags & IOU_PBUF_RING_MMAP))
69662306a36Sopenharmony_ci		ret = io_pin_pbuf_ring(&reg, bl);
69762306a36Sopenharmony_ci	else
69862306a36Sopenharmony_ci		ret = io_alloc_pbuf_ring(ctx, &reg, bl);
69962306a36Sopenharmony_ci
70062306a36Sopenharmony_ci	if (!ret) {
70162306a36Sopenharmony_ci		bl->nr_entries = reg.ring_entries;
70262306a36Sopenharmony_ci		bl->mask = reg.ring_entries - 1;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		io_buffer_add_list(ctx, bl, reg.bgid);
70562306a36Sopenharmony_ci		return 0;
70662306a36Sopenharmony_ci	}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci	kfree_rcu(free_bl, rcu);
70962306a36Sopenharmony_ci	return ret;
71062306a36Sopenharmony_ci}
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ciint io_unregister_pbuf_ring(struct io_ring_ctx *ctx, void __user *arg)
71362306a36Sopenharmony_ci{
71462306a36Sopenharmony_ci	struct io_uring_buf_reg reg;
71562306a36Sopenharmony_ci	struct io_buffer_list *bl;
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	lockdep_assert_held(&ctx->uring_lock);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	if (copy_from_user(&reg, arg, sizeof(reg)))
72062306a36Sopenharmony_ci		return -EFAULT;
72162306a36Sopenharmony_ci	if (reg.resv[0] || reg.resv[1] || reg.resv[2])
72262306a36Sopenharmony_ci		return -EINVAL;
72362306a36Sopenharmony_ci	if (reg.flags)
72462306a36Sopenharmony_ci		return -EINVAL;
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci	bl = io_buffer_get_list(ctx, reg.bgid);
72762306a36Sopenharmony_ci	if (!bl)
72862306a36Sopenharmony_ci		return -ENOENT;
72962306a36Sopenharmony_ci	if (!bl->is_mapped)
73062306a36Sopenharmony_ci		return -EINVAL;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	__io_remove_buffers(ctx, bl, -1U);
73362306a36Sopenharmony_ci	if (bl->bgid >= BGID_ARRAY) {
73462306a36Sopenharmony_ci		xa_erase(&ctx->io_bl_xa, bl->bgid);
73562306a36Sopenharmony_ci		kfree_rcu(bl, rcu);
73662306a36Sopenharmony_ci	}
73762306a36Sopenharmony_ci	return 0;
73862306a36Sopenharmony_ci}
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_civoid *io_pbuf_get_address(struct io_ring_ctx *ctx, unsigned long bgid)
74162306a36Sopenharmony_ci{
74262306a36Sopenharmony_ci	struct io_buffer_list *bl;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci	bl = __io_buffer_get_list(ctx, smp_load_acquire(&ctx->io_bl), bgid);
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ci	if (!bl || !bl->is_mmap)
74762306a36Sopenharmony_ci		return NULL;
74862306a36Sopenharmony_ci	/*
74962306a36Sopenharmony_ci	 * Ensure the list is fully setup. Only strictly needed for RCU lookup
75062306a36Sopenharmony_ci	 * via mmap, and in that case only for the array indexed groups. For
75162306a36Sopenharmony_ci	 * the xarray lookups, it's either visible and ready, or not at all.
75262306a36Sopenharmony_ci	 */
75362306a36Sopenharmony_ci	if (!smp_load_acquire(&bl->is_ready))
75462306a36Sopenharmony_ci		return NULL;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	return bl->buf_ring;
75762306a36Sopenharmony_ci}
75862306a36Sopenharmony_ci
75962306a36Sopenharmony_ci/*
76062306a36Sopenharmony_ci * Called at or after ->release(), free the mmap'ed buffers that we used
76162306a36Sopenharmony_ci * for memory mapped provided buffer rings.
76262306a36Sopenharmony_ci */
76362306a36Sopenharmony_civoid io_kbuf_mmap_list_free(struct io_ring_ctx *ctx)
76462306a36Sopenharmony_ci{
76562306a36Sopenharmony_ci	struct io_buf_free *ibf;
76662306a36Sopenharmony_ci	struct hlist_node *tmp;
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	hlist_for_each_entry_safe(ibf, tmp, &ctx->io_buf_list, list) {
76962306a36Sopenharmony_ci		hlist_del(&ibf->list);
77062306a36Sopenharmony_ci		io_mem_free(ibf->mem);
77162306a36Sopenharmony_ci		kfree(ibf);
77262306a36Sopenharmony_ci	}
77362306a36Sopenharmony_ci}
774