io_uring/memmap: fix non-compound alloc fallback with memcg accounting

io_region_allocate_pages() first tries io_mem_alloc_compound(). If that
fails, it uses alloc_pages_bulk_node() to allocate separate pages.

The bulk allocator does not support memcg accounting. __GFP_ACCOUNT is
unconditionally supplied, so when memcg_kmem_online() is true, it only
allocates one page. For a multi-page request, io_uring treats this short
result as failure and returns ENOMEM, even when the memcg has enough
space for all pages.

When this happens, fill the rest of the request with order 0 allocations
via alloc_page(), which support memcg accounting. This maintains the
existing fast path, while fixing the incorrect ENOMEM return when memcg
is used.

Signed-off-by: David Wei <dw@davidwei.uk>
Reviewed-by: Gabriel Krisman Bertazi <krisman@suse.de>
Fixes: 1e21df691f ("io_uring/memmap: implement kernel allocated regions")
Link: https://patch.msgid.link/20261001181752.537767-1-dw@davidwei.uk
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
David Wei 2026-10-01 11:17:52 -07:00 committed by Jens Axboe
parent 13d3783a55
commit 68477e4c56

View File

@ -180,6 +180,7 @@ static int io_region_allocate_pages(struct io_mapped_region *mr,
size_t size = io_region_size(mr);
unsigned long nr_allocated;
struct page **pages;
struct page *page;
pages = kvmalloc_objs(*pages, mr->nr_pages, gfp);
if (!pages)
@ -192,6 +193,13 @@ static int io_region_allocate_pages(struct io_mapped_region *mr,
nr_allocated = alloc_pages_bulk_node(gfp, NUMA_NO_NODE,
mr->nr_pages, pages);
while (nr_allocated < mr->nr_pages) {
page = alloc_page(gfp);
if (!page)
break;
pages[nr_allocated++] = page;
}
if (nr_allocated != mr->nr_pages) {
if (nr_allocated)
release_pages(pages, nr_allocated);