[PATCH v4] malloc: Support hugepages in mremap_chunk
Adhemerval Zanella Netto
adhemerval.zanella@linaro.org
Tue Aug 26 17:06:02 GMT 2025
On 26/08/25 07:23, William Hunt wrote:
> Add mremap_chunk support for mmap()ed chunks using hugepages by accounting for
> their alignment, to prevent the mremap call failing in most cases where the
> size passed is not a hugepage size multiple. It also improves robustness for
> reallocating hugepages since mremap is much less likely to fail, so running
> out of memory when reallocating a larger size and having to copy the old
> contents after mremap fails is also less likely.
>
> To track whether an mmap()ed chunk uses hugepages, have a flag in the lowest
> bit of the mchunk_prev_size field which is set after a call to sysmalloc_mmap,
> and accessed later in mremap_chunk. Create macros for getting and setting this
> bit, and for mapping the bit off when accessing the field for mmap()ed chunks.
> Since the alignment cannot be lower than 8 bits, this flag cannot affect the
> alignment data.
>
> Add malloc/tst-tcfree4-malloc-check to the tests-exclude-malloc-check list as
> malloc-check prevents the tcache from being used to store chunks. This test
> caused failures due to a bug in mem2chunk_check to be fixed in a later patch.
>
> Changes from v1:
> - Change macros to inlined functions.
> - Added malloc/tst-tcfree4 to tests-exclude-malloc-check as tcache is disabled.
> Changes from v2:
> - Removed a first mem2chunk_check fix, should be fully fixed in another patch.
> Changes from v3:
> - Added DCO to clarify I am currently covered by Arm's copyright assignment.
>
> Passed regress for THPs, neither and HPs using overcommit pages, OK for commit?
>
> Signed-off-by: William Hunt <william.hunt@arm.com>
LGTM, thanks.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
> ---
> malloc/Makefile | 1 +
> malloc/malloc-check.c | 4 ++--
> malloc/malloc.c | 41 +++++++++++++++++++++++++++++++++++------
> 3 files changed, 38 insertions(+), 8 deletions(-)
>
> diff --git a/malloc/Makefile b/malloc/Makefile
> index 83f6c873e8..a9a0e87264 100644
> --- a/malloc/Makefile
> +++ b/malloc/Makefile
> @@ -114,6 +114,7 @@ tests-exclude-malloc-check = \
> tst-memalign-3 \
> tst-mxfast \
> tst-safe-linking \
> + tst-tcfree4 \
> # tests-exclude-malloc-check
>
> # Run all tests with MALLOC_CHECK_=3
> diff --git a/malloc/malloc-check.c b/malloc/malloc-check.c
> index 9532316a29..7731eaeec5 100644
> --- a/malloc/malloc-check.c
> +++ b/malloc/malloc-check.c
> @@ -151,8 +151,8 @@ mem2chunk_check (void *mem, unsigned char **magic_p)
> offset != 0x200 && offset != 0x400 && offset != 0x800 && offset != 0x1000 &&
> offset < 0x2000) ||
> !chunk_is_mmapped (p) || prev_inuse (p) ||
> - ((((unsigned long) p - prev_size (p)) & page_mask) != 0) ||
> - ((prev_size (p) + sz) & page_mask) != 0)
> + ((((unsigned long) p - prev_size_mmap (p)) & page_mask) != 0) ||
> + ((prev_size_mmap (p) + sz) & page_mask) != 0)
> return NULL;
>
> for (sz = CHUNK_HDR_SZ + memsize (p) - 1;
Ok.
> diff --git a/malloc/malloc.c b/malloc/malloc.c
> index e08873cad5..55688d4319 100644
> --- a/malloc/malloc.c
> +++ b/malloc/malloc.c
> @@ -1477,6 +1477,30 @@ tag_new_usable (void *ptr)
> return ptr;
> }
>
> +/* HP page used for an mmap()'ed chunk. */
> +#define MMAP_HP 0x1
> +
> +/* Check for HP usage from an mmap()'ed chunk. */
> +static __always_inline bool
> +mmap_is_hp (mchunkptr p)
> +{
> + return prev_size (p) & MMAP_HP;
> +}
> +
> +/* Set HP advised field for an mmap()'ed chunk. */
> +static __always_inline void
> +set_mmap_is_hp (mchunkptr p)
> +{
> + prev_size (p) |= MMAP_HP;
> +}
> +
> +/* Get an mmap()ed chunk's offset, ignoring huge page bits. */
> +static __always_inline size_t
> +prev_size_mmap (mchunkptr p)
> +{
> + return prev_size (p) & ~MMAP_HP;
> +}
> +
> /*
> -------------------- Internal data structures --------------------
>
Ok.
> @@ -2105,7 +2129,7 @@ do_check_chunk (mstate av, mchunkptr p)
> else
> {
> /* chunk is page-aligned */
> - assert (((prev_size (p) + sz) & (GLRO (dl_pagesize) - 1)) == 0);
> + assert (((prev_size_mmap (p) + sz) & (GLRO (dl_pagesize) - 1)) == 0);
> /* mem is aligned */
> assert (!misaligned_chunk (p));
> }
> @@ -2429,6 +2453,11 @@ sysmalloc_mmap (INTERNAL_SIZE_T nb, size_t pagesize, int extra_flags)
> set_prev_size (p, padding);
> set_head (p, (size - padding) | IS_MMAPPED);
>
> + /* Must also check whether huge pages were used in the mmap call
> + and this is not the fallback call after using huge pages failed */
> + if (__glibc_unlikely (extra_flags & mp_.hp_flags))
> + set_mmap_is_hp (p);
> +
> /* update statistics */
> int new = atomic_fetch_add_relaxed (&mp_.n_mmaps, 1) + 1;
> atomic_max (&mp_.max_n_mmaps, new);
> @@ -2982,8 +3011,8 @@ munmap_chunk (mchunkptr p)
> assert (chunk_is_mmapped (p));
>
> uintptr_t mem = (uintptr_t) chunk2mem (p);
> - uintptr_t block = (uintptr_t) p - prev_size (p);
> - size_t total_size = prev_size (p) + size;
> + uintptr_t block = (uintptr_t) p - prev_size_mmap (p);
> + size_t total_size = prev_size_mmap (p) + size;
> /* Unfortunately we have to do the compilers job by hand here. Normally
> we would test BLOCK and TOTAL-SIZE separately for compliance with the
> page size. But gcc does not recognize the optimization possibility
> @@ -3007,8 +3036,8 @@ munmap_chunk (mchunkptr p)
> static mchunkptr
> mremap_chunk (mchunkptr p, size_t new_size)
> {
> - size_t pagesize = GLRO (dl_pagesize);
> - INTERNAL_SIZE_T offset = prev_size (p);
> + size_t pagesize = mmap_is_hp (p) ? mp_.hp_pagesize : GLRO (dl_pagesize);
> + INTERNAL_SIZE_T offset = prev_size_mmap (p);
> INTERNAL_SIZE_T size = chunksize (p);
> char *cp;
>
> @@ -3040,7 +3069,7 @@ mremap_chunk (mchunkptr p, size_t new_size)
>
> assert (!misaligned_chunk (p));
>
> - assert (prev_size (p) == offset);
> + assert (prev_size_mmap (p) == offset);
> set_head (p, (new_size - offset) | IS_MMAPPED);
>
> INTERNAL_SIZE_T new;
Ok.
More information about the Libc-alpha
mailing list