Re: [PATCH v2] setup: dynamically detect default huge page size
Gabriel Krisman Bertazi <[email protected]> Tue, 07 Jul 2026 12:38:38 -0400
| Newsgroups | org.kernel.vger.io-uring |
|---|---|
| Organization | SUSE |
| Message-ID | <[email protected]> |
Prateek <[email protected]> writes: > Replaces the hardcoded 2MB huge page size with dynamic detection by > parsing /proc/meminfo. This fixes no-mmap allocation failures on > architectures with different default huge page sizes (like ARM64 > which often uses 512MB) or x86 systems configured for 1GB pages. > > - Safely parses /proc/meminfo without allocating memory. > - Adds a __uring_memcmp shim for CONFIG_NOLIBC builds, allowing > setup.c to use standard memcmp for the Hugepagesize: match. > - Drops the MAP_HUGE_2MB mmap flag to allow the kernel to correctly > apply the system's default huge page size. > - Falls back safely to 2MB if /proc/meminfo is unreadable. Reviewed-by: Gabriel Krisman Bertazi <[email protected]> > > Signed-off-by: Prateek <[email protected]> > --- > Changes in v2: > - Initialized hps explicitly to 0. > - Replaced the char-by-char Hugepagesize comparison with a new __uring_memcmp helper. > - Removed the redundant ret variable and simplified the fallback assignment using a ternary operator. > > src/lib.h | 2 ++ > src/nolibc.c | 19 +++++++++++++ > src/setup.c | 75 +++++++++++++++++++++++++++++++++++++++++----------- > 3 files changed, 80 insertions(+), 16 deletions(-) > > diff --git a/src/lib.h b/src/lib.h > index 4d32d3e1..463dd4b5 100644 > --- a/src/lib.h > +++ b/src/lib.h > @@ -41,10 +41,12 @@ > void *__uring_memset(void *s, int c, size_t n); > void *__uring_malloc(size_t len); > void __uring_free(void *p); > +int __uring_memcmp(const void *s1, const void *s2, size_t n); > > #define malloc(LEN) __uring_malloc(LEN) > #define free(PTR) __uring_free(PTR) > #define memset(PTR, C, LEN) __uring_memset(PTR, C, LEN) > +#define memcmp(S1, S2, LEN) __uring_memcmp(S1, S2, LEN) > #endif > > #endif /* #ifndef LIBURING_LIB_H */ > diff --git a/src/nolibc.c b/src/nolibc.c > index 88b1494a..14ede500 100644 > --- a/src/nolibc.c > +++ b/src/nolibc.c > @@ -25,6 +25,25 @@ void *__uring_memset(void *s, int c, size_t n) > return s; > } > > +int __uring_memcmp(const void *s1, const void *s2, size_t n) > +{ > + size_t i; > + const unsigned char *p1 = s1, *p2 = s2; > + > + for (i = 0; i < n; i++) { > + if (p1[i] != p2[i]) > + return p1[i] - p2[i]; > + > + /* > + * An empty inline ASM to avoid auto-vectorization > + * because it's too bloated for liburing. > + */ > + __asm__ volatile (""); > + } > + > + return 0; > +} > + > struct uring_heap { > size_t len; > char user_p[] __attribute__((__aligned__)); > diff --git a/src/setup.c b/src/setup.c > index ea6f11fd..88f86784 100644 > --- a/src/setup.c > +++ b/src/setup.c > @@ -220,15 +220,58 @@ __cold int io_uring_ring_dontfork(struct io_uring *ring) > return 0; > } > > -#ifndef MAP_HUGE_SHIFT > -#define MAP_HUGE_SHIFT 26 > -#endif > -#ifndef MAP_HUGE_2MB > -#define MAP_HUGE_2MB (21U << MAP_HUGE_SHIFT) > -#endif > > -/* FIXME */ > -static size_t huge_page_size = 2 * 1024 * 1024; > +static size_t get_huge_page_size(void) > +{ > + static size_t hps = 0; > + char buf[4096]; > + char *p, *end; > + unsigned long val = 0; > + ssize_t n; > + int fd; > + > + if (hps) > + return hps; > + > + fd = __sys_open("/proc/meminfo", O_RDONLY, 0); > + if (fd < 0) > + goto out; > + > + n = __sys_read(fd, buf, sizeof(buf) - 1); > + __sys_close(fd); > + if (n <= 0) > + goto out; > + buf[n] = '\0'; > + > + /* > + * Scan line-by-line for "Hugepagesize:". > + */ > + p = buf; > + end = buf + n; > + while (p < end) { > + /* Check if this line starts with "Hugepagesize:" (13 chars) */ > + if (p + 13 <= end && !memcmp(p, "Hugepagesize:", 13)) { > + p += 13; > + while (p < end && (*p == ' ' || *p == '\t')) > + p++; > + val = 0; > + while (p < end && *p >= '0' && *p <= '9') { > + val = val * 10 + (*p - '0'); > + p++; > + } > + break; > + } > + /* Advance to next line */ > + while (p < end && *p != '\n') > + p++; > + if (p < end) > + p++; > + } > +out: > + hps = val ? val * 1024 : 2 * 1024 * 1024; > + return hps; > +} > + > > #define KRING_SIZE 64 > > @@ -261,13 +304,13 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p, > mem_used = (mem_used + page_size - 1) & ~(page_size - 1); > > /* > - * A maxed-out number of CQ entries with IORING_SETUP_CQE32 fills a 2MB > - * huge page by itself, so the SQ entries won't fit in the same huge > - * page. For SQEs, that shouldn't be possible given KERN_MAX_ENTRIES, > + * A maxed-out number of CQ entries with IORING_SETUP_CQE32 can fill a > + * single huge page by itself, so the SQ entries won't fit in the same > + * huge page. For SQEs, that shouldn't be possible given KERN_MAX_ENTRIES, > * but check that too to future-proof (e.g. against different huge page > * sizes). Bail out early so we don't overrun. > */ > - if (!buf && (sqes_mem > huge_page_size || ring_mem > huge_page_size)) > + if (!buf && (sqes_mem > get_huge_page_size() || ring_mem > get_huge_page_size())) > return -ENOMEM; > > if (buf) { > @@ -279,8 +322,8 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p, > if (sqes_mem <= page_size) > buf_size = page_size; > else { > - buf_size = huge_page_size; > - map_hugetlb = MAP_HUGETLB | MAP_HUGE_2MB; > + buf_size = get_huge_page_size(); > + map_hugetlb = MAP_HUGETLB; > } > sqes_size = buf_size; > ptr = __sys_mmap(NULL, sqes_size, PROT_READ|PROT_WRITE, > @@ -302,8 +345,8 @@ static int io_uring_alloc_huge(unsigned entries, struct io_uring_params *p, > if (ring_mem <= page_size) > buf_size = page_size; > else { > - buf_size = huge_page_size; > - map_hugetlb = MAP_HUGETLB | MAP_HUGE_2MB; > + buf_size = get_huge_page_size(); > + map_hugetlb = MAP_HUGETLB; > } > ptr = __sys_mmap(NULL, buf_size, PROT_READ|PROT_WRITE, > MAP_SHARED|MAP_ANONYMOUS|map_hugetlb, > -- > 2.43.0 > -- Gabriel Krisman Bertazi