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(®, 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(®, bl); 69762306a36Sopenharmony_ci else 69862306a36Sopenharmony_ci ret = io_alloc_pbuf_ring(ctx, ®, 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(®, 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