[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