Skip to content

Commit 1e21df6

Browse files
isilenceaxboe
authored andcommitted
io_uring/memmap: implement kernel allocated regions
Allow the kernel to allocate memory for a region. That's the classical way SQ/CQ are allocated. It's not yet useful to user space as there is no way to mmap it, which is why it's explicitly disabled in io_register_mem_region(). Signed-off-by: Pavel Begunkov <[email protected]> Link: https://lore.kernel.org/r/7b8c40e6542546bbf93f4842a9a42a7373b81e0d.1732886067.git.asml.silence@gmail.com Signed-off-by: Jens Axboe <[email protected]>
1 parent 4b851d2 commit 1e21df6

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

io_uring/memmap.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,39 @@ static int io_region_pin_pages(struct io_ring_ctx *ctx,
273273
return 0;
274274
}
275275

276+
static int io_region_allocate_pages(struct io_ring_ctx *ctx,
277+
struct io_mapped_region *mr,
278+
struct io_uring_region_desc *reg)
279+
{
280+
gfp_t gfp = GFP_KERNEL_ACCOUNT | __GFP_ZERO | __GFP_NOWARN;
281+
unsigned long size = mr->nr_pages << PAGE_SHIFT;
282+
unsigned long nr_allocated;
283+
struct page **pages;
284+
void *p;
285+
286+
pages = kvmalloc_array(mr->nr_pages, sizeof(*pages), gfp);
287+
if (!pages)
288+
return -ENOMEM;
289+
290+
p = io_mem_alloc_compound(pages, mr->nr_pages, size, gfp);
291+
if (!IS_ERR(p)) {
292+
mr->flags |= IO_REGION_F_SINGLE_REF;
293+
mr->pages = pages;
294+
return 0;
295+
}
296+
297+
nr_allocated = alloc_pages_bulk_array_node(gfp, NUMA_NO_NODE,
298+
mr->nr_pages, pages);
299+
if (nr_allocated != mr->nr_pages) {
300+
if (nr_allocated)
301+
release_pages(pages, nr_allocated);
302+
kvfree(pages);
303+
return -ENOMEM;
304+
}
305+
mr->pages = pages;
306+
return 0;
307+
}
308+
276309
int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
277310
struct io_uring_region_desc *reg)
278311
{
@@ -283,9 +316,10 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
283316
return -EFAULT;
284317
if (memchr_inv(&reg->__resv, 0, sizeof(reg->__resv)))
285318
return -EINVAL;
286-
if (reg->flags != IORING_MEM_REGION_TYPE_USER)
319+
if (reg->flags & ~IORING_MEM_REGION_TYPE_USER)
287320
return -EINVAL;
288-
if (!reg->user_addr)
321+
/* user_addr should be set IFF it's a user memory backed region */
322+
if ((reg->flags & IORING_MEM_REGION_TYPE_USER) != !!reg->user_addr)
289323
return -EFAULT;
290324
if (!reg->size || reg->mmap_offset || reg->id)
291325
return -EINVAL;
@@ -304,7 +338,10 @@ int io_create_region(struct io_ring_ctx *ctx, struct io_mapped_region *mr,
304338
}
305339
mr->nr_pages = nr_pages;
306340

307-
ret = io_region_pin_pages(ctx, mr, reg);
341+
if (reg->flags & IORING_MEM_REGION_TYPE_USER)
342+
ret = io_region_pin_pages(ctx, mr, reg);
343+
else
344+
ret = io_region_allocate_pages(ctx, mr, reg);
308345
if (ret)
309346
goto out_free;
310347

io_uring/register.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,6 +589,8 @@ static int io_register_mem_region(struct io_ring_ctx *ctx, void __user *uarg)
589589
if (copy_from_user(&rd, rd_uptr, sizeof(rd)))
590590
return -EFAULT;
591591

592+
if (!(rd.flags & IORING_MEM_REGION_TYPE_USER))
593+
return -EINVAL;
592594
if (memchr_inv(&reg.__resv, 0, sizeof(reg.__resv)))
593595
return -EINVAL;
594596
if (reg.flags & ~IORING_MEM_REGION_REG_WAIT_ARG)

0 commit comments

Comments
 (0)