With --huge-unlink=never the hugepage files are kept and mapped again
on the next run. The kernel only zeroes a hugepage the first time it is
mapped from a given file, so these pages still hold the previous run's
content.

The dynamic memory path records this by setting RTE_MEMSEG_FLAG_DIRTY
in alloc_seg(). The legacy path in remap_segment() never sets ms->flags,
so rte_zmalloc_socket() skips the memset and returns stale data.

With --legacy-mem --huge-unlink=never, a second process gets non-zeroed
memory from rte_zmalloc(). mlx5 with sys_mem_en disabled allocates its
internal structures through rte_zmalloc_socket() and then reads stale
pointers from them, which crashes in mlx5_ipool_malloc_cache() during
probe:

  SEGV on unknown address 0x000000000308
    #0 _mlx5_ipool_malloc_cache drivers/net/mlx5/mlx5_utils.c:550
    ...
    #16 mlx5_alloc_shared_dr drivers/net/mlx5/linux/mlx5_os.c:628

Set RTE_MEMSEG_FLAG_DIRTY on segments remapped in legacy mode whenever
existing hugepage files are reused, matching the dynamic path. Why a
reused page is dirty is documented on unlink_existing.

Fixes: 32b4771cd8ef ("eal/linux: allow hugepage file reuse")
Cc: [email protected]

Suggested-by: Thomas Monjalon <[email protected]>
Signed-off-by: Maayan Kashani <[email protected]>
---
 lib/eal/common/eal_internal_cfg.h | 8 +++++++-
 lib/eal/linux/eal_memory.c        | 5 +++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/lib/eal/common/eal_internal_cfg.h 
b/lib/eal/common/eal_internal_cfg.h
index 07cd35167dd..1221e03253f 100644
--- a/lib/eal/common/eal_internal_cfg.h
+++ b/lib/eal/common/eal_internal_cfg.h
@@ -44,7 +44,13 @@ struct simd_bitwidth {
 struct hugepage_file_discipline {
        /** Unlink files before mapping them to leave no trace in hugetlbfs. */
        bool unlink_before_mapping;
-       /** Unlink existing files at startup, re-create them before mapping. */
+       /**
+        * Unlink existing files at startup and re-create them before mapping.
+        * If false, the files are kept and mapped again. The kernel zeroes a
+        * hugepage only the first time it is mapped from a given file, so
+        * reused pages still hold the previous content and must be treated
+        * as dirty.
+        */
        bool unlink_existing;
 };
 
diff --git a/lib/eal/linux/eal_memory.c b/lib/eal/linux/eal_memory.c
index 614f31a308e..0edf66eea5e 100644
--- a/lib/eal/linux/eal_memory.c
+++ b/lib/eal/linux/eal_memory.c
@@ -692,10 +692,10 @@ remap_segment(struct hugepage_file *hugepages, int 
seg_start, int seg_end)
        uint64_t page_sz;
        size_t memseg_len;
        int socket_id;
-#ifndef RTE_ARCH_64
        const struct internal_config *internal_conf =
                eal_get_internal_configuration();
-#endif
+       const bool dirty = !internal_conf->hugepage_file.unlink_existing;
+
        page_sz = hugepages[seg_start].size;
        socket_id = hugepages[seg_start].socket_id;
        seg_len = seg_end - seg_start;
@@ -816,6 +816,7 @@ remap_segment(struct hugepage_file *hugepages, int 
seg_start, int seg_end)
                ms->socket_id = hfile->socket_id;
                ms->nchannel = rte_memory_get_nchannel();
                ms->nrank = rte_memory_get_nrank();
+               ms->flags = dirty ? RTE_MEMSEG_FLAG_DIRTY : 0;
 
                rte_fbarray_set_used(arr, ms_idx);
 
-- 
2.25.1

Reply via email to