From e0a41b8c471b32fc855bcd016d97bbb935fd36b0 Mon Sep 17 00:00:00 2001 From: Roy Shterman Date: Mon, 22 Feb 2021 12:41:31 +0200 Subject: [PATCH] mem: fix freeing segments in --huge-unlink mode [ upstream commit edf20bd8a55192616e4a0f26c346b55ddbac1d81 ] When using huge_unlink we unlink the segment right after allocation. Although we unlink the file we keep the fd in fd_list so file still exist just the path deleted. When freeing the hugepage we need to close the fd and assign it with (-1) in fd_list for the page to be released. The current flow fails rte_malloc in the following flow when working with --huge-unlink option: 1. alloc_seg() for segment A - We allocate a segment, unlink the path to the segment and keep the file descriptor in fd_list. 2. free_seg() for segment A - We clear the segment metadata and return - without closing fd or assigning (-1) in fd list. 3. alloc_seg() for segment A again - We find segment A as available, try to allocate it, find the old fd in fd_list try to unlink it as part of alloc_seg() but failed because path doesn't exist. The impact of such error is falsely failing rte_malloc() although we have hugepages available. Fixes: d435aad37da7 ("mem: support --huge-unlink mode") Signed-off-by: Roy Shterman Acked-by: Anatoly Burakov --- lib/librte_eal/linux/eal_memalloc.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/lib/librte_eal/linux/eal_memalloc.c b/lib/librte_eal/linux/eal_memalloc.c index 6dc1b2baecd..c590d604306 100644 --- a/lib/librte_eal/linux/eal_memalloc.c +++ b/lib/librte_eal/linux/eal_memalloc.c @@ -709,7 +709,6 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi, uint64_t map_offset; char path[PATH_MAX]; int fd, ret = 0; - bool exit_early; const struct internal_config *internal_conf = eal_get_internal_configuration(); @@ -725,17 +724,8 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi, eal_mem_set_dump(ms->addr, ms->len, false); - exit_early = false; - /* if we're using anonymous hugepages, nothing to be done */ - if (internal_conf->in_memory && !memfd_create_supported) - exit_early = true; - - /* if we've already unlinked the page, nothing needs to be done */ - if (!internal_conf->in_memory && internal_conf->hugepage_unlink) - exit_early = true; - - if (exit_early) { + if (internal_conf->in_memory && !memfd_create_supported) { memset(ms, 0, sizeof(*ms)); return 0; } @@ -761,7 +751,7 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi, /* if we're able to take out a write lock, we're the last one * holding onto this page. */ - if (!internal_conf->in_memory) { + if (!internal_conf->in_memory && !internal_conf->hugepage_unlink) { ret = lock(fd, LOCK_EX); if (ret >= 0) { /* no one else is using this page */