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