]> git.droids-corp.org - dpdk.git/commitdiff
mem: detach memsegs on cleanup
authorAnatoly Burakov <anatoly.burakov@intel.com>
Mon, 14 Sep 2020 13:04:05 +0000 (14:04 +0100)
committerDavid Marchand <david.marchand@redhat.com>
Wed, 3 Mar 2021 09:05:23 +0000 (10:05 +0100)
Currently, we don't detach the shared memory on EAL cleanup, which
leaves the page table descriptors still holding on to the file
descriptors as well as memory space occupied by them. Fix it by adding
another detach stage that closes the internal memory allocator resource
references, detaches shared fbarrays and unmaps the shared mem config.

Bugzilla ID: 380
Bugzilla ID: 381

Signed-off-by: Anatoly Burakov <anatoly.burakov@intel.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
lib/librte_eal/common/eal_common_memory.c
lib/librte_eal/common/eal_memalloc.h
lib/librte_eal/common/eal_private.h
lib/librte_eal/freebsd/eal.c
lib/librte_eal/freebsd/eal_memalloc.c
lib/librte_eal/linux/eal.c
lib/librte_eal/linux/eal_memalloc.c
lib/librte_eal/windows/eal.c
lib/librte_eal/windows/eal_memalloc.c

index 33917fa835ec78f07099c06931e777f3071b5148..0e99986d3ddbad4d75b2dc3570df96c7cc8512ca 100644 (file)
@@ -1002,6 +1002,60 @@ rte_extmem_detach(void *va_addr, size_t len)
        return sync_memory(va_addr, len, false);
 }
 
+/* detach all EAL memory */
+int
+rte_eal_memory_detach(void)
+{
+       struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+       size_t page_sz = rte_mem_page_size();
+       unsigned int i;
+
+       rte_rwlock_write_lock(&mcfg->memory_hotplug_lock);
+
+       /* detach internal memory subsystem data first */
+       if (eal_memalloc_cleanup())
+               RTE_LOG(ERR, EAL, "Could not release memory subsystem data\n");
+
+       for (i = 0; i < RTE_DIM(mcfg->memsegs); i++) {
+               struct rte_memseg_list *msl = &mcfg->memsegs[i];
+
+               /* skip uninitialized segments */
+               if (msl->base_va == NULL)
+                       continue;
+               /*
+                * external segments are supposed to be detached at this point,
+                * but if they aren't, we can't really do anything about it,
+                * because if we skip them here, they'll become invalid after
+                * we unmap the memconfig anyway. however, if this is externally
+                * referenced memory, we have no business unmapping it.
+                */
+               if (!msl->external)
+                       if (rte_mem_unmap(msl->base_va, msl->len) != 0)
+                               RTE_LOG(ERR, EAL, "Could not unmap memory: %s\n",
+                                               strerror(errno));
+
+               /*
+                * we are detaching the fbarray rather than destroying because
+                * other processes might still reference this fbarray, and we
+                * have no way of knowing if they still do.
+                */
+               if (rte_fbarray_detach(&msl->memseg_arr))
+                       RTE_LOG(ERR, EAL, "Could not detach fbarray: %s\n",
+                                       rte_strerror(rte_errno));
+       }
+       rte_rwlock_write_unlock(&mcfg->memory_hotplug_lock);
+
+       /*
+        * we've detached the memseg lists, so we can unmap the shared mem
+        * config - we can't zero it out because it might still be referenced
+        * by other processes.
+        */
+       rte_mem_unmap(mcfg, RTE_ALIGN(sizeof(*mcfg), page_sz));
+       rte_eal_get_configuration()->mem_config = NULL;
+
+       return 0;
+}
+
 /* init memory subsystem */
 int
 rte_eal_memory_init(void)
index e953cd84e6ce4e4f7c92169c1ee693c1563fdc25..ebc3a6f6c1f5b0c02a284acfb21bc6071e8b6603 100644 (file)
@@ -93,4 +93,7 @@ eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset);
 int
 eal_memalloc_init(void);
 
+int
+eal_memalloc_cleanup(void);
+
 #endif /* EAL_MEMALLOC_H */
index 4684c4c7df195ff328c980184055f42579ef06b1..b8a0d200210f4d6b3a520213336d5fd73c2d29b5 100644 (file)
@@ -433,6 +433,13 @@ int rte_eal_hugepage_init(void);
  */
 int rte_eal_hugepage_attach(void);
 
+/**
+ * Detaches all memory mappings from a process.
+ *
+ * This function is private to the EAL.
+ */
+int rte_eal_memory_detach(void);
+
 /**
  * Find a bus capable of identifying a device.
  *
index 51478358c77e67e8bf1986343fe883d9ad0347cc..e2cdad528376da48f6befc597ddee942f54024e4 100644 (file)
@@ -964,6 +964,8 @@ rte_eal_cleanup(void)
                eal_get_internal_configuration();
        rte_service_finalize();
        rte_mp_channel_cleanup();
+       /* after this point, any DPDK pointers will become dangling */
+       rte_eal_memory_detach();
        rte_trace_save();
        eal_trace_fini();
        eal_cleanup_config(internal_conf);
index 6893448db7176cf33d6be0c058f965b168c1188b..00ab02cb637f899d7dd68410ea1a9d0b96ce0d0f 100644 (file)
@@ -74,6 +74,11 @@ eal_memalloc_get_seg_fd_offset(int list_idx __rte_unused,
        return -ENOTSUP;
 }
 
+int eal_memalloc_cleanup(void)
+{
+       return 0;
+}
+
 int
 eal_memalloc_init(void)
 {
index 32b48c3de9a5ee8e01c3aab90c2251d140dc8606..6c34ac89038690b268dfd9847817c45a1095d4d9 100644 (file)
@@ -1360,6 +1360,8 @@ rte_eal_cleanup(void)
                rte_memseg_walk(mark_freeable, NULL);
        rte_service_finalize();
        rte_mp_channel_cleanup();
+       /* after this point, any DPDK pointers will become dangling */
+       rte_eal_memory_detach();
        rte_trace_save();
        eal_trace_fini();
        eal_cleanup_config(internal_conf);
index 6dc1b2baecdc71a147348251f3f6e8c18cc753f7..00e2662c15aed3d18fbd816a7b111b8e678260a4 100644 (file)
@@ -1441,6 +1441,31 @@ secondary_msl_create_walk(const struct rte_memseg_list *msl,
        return 0;
 }
 
+static int
+secondary_msl_destroy_walk(const struct rte_memseg_list *msl,
+               void *arg __rte_unused)
+{
+       struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+       struct rte_memseg_list *local_msl;
+       int msl_idx, ret;
+
+       if (msl->external)
+               return 0;
+
+       msl_idx = msl - mcfg->memsegs;
+       local_msl = &local_memsegs[msl_idx];
+
+       ret = rte_fbarray_destroy(&local_msl->memseg_arr);
+       if (ret < 0) {
+               RTE_LOG(ERR, EAL, "Cannot destroy local memory map\n");
+               return -1;
+       }
+       local_msl->base_va = NULL;
+       local_msl->len = 0;
+
+       return 0;
+}
+
 static int
 alloc_list(int list_idx, int len)
 {
@@ -1473,6 +1498,34 @@ alloc_list(int list_idx, int len)
        return 0;
 }
 
+static int
+destroy_list(int list_idx)
+{
+       const struct internal_config *internal_conf =
+                       eal_get_internal_configuration();
+
+       /* single-file segments mode does not need fd list */
+       if (!internal_conf->single_file_segments) {
+               int *fds = fd_list[list_idx].fds;
+               int i;
+               /* go through each fd and ensure it's closed */
+               for (i = 0; i < fd_list[list_idx].len; i++) {
+                       if (fds[i] >= 0) {
+                               close(fds[i]);
+                               fds[i] = -1;
+                       }
+               }
+               free(fds);
+               fd_list[list_idx].fds = NULL;
+               fd_list[list_idx].len = 0;
+       } else if (fd_list[list_idx].memseg_list_fd >= 0) {
+               close(fd_list[list_idx].memseg_list_fd);
+               fd_list[list_idx].count = 0;
+               fd_list[list_idx].memseg_list_fd = -1;
+       }
+       return 0;
+}
+
 static int
 fd_list_create_walk(const struct rte_memseg_list *msl,
                void *arg __rte_unused)
@@ -1490,6 +1543,20 @@ fd_list_create_walk(const struct rte_memseg_list *msl,
        return alloc_list(msl_idx, len);
 }
 
+static int
+fd_list_destroy_walk(const struct rte_memseg_list *msl, void *arg __rte_unused)
+{
+       struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+       int msl_idx;
+
+       if (msl->external)
+               return 0;
+
+       msl_idx = msl - mcfg->memsegs;
+
+       return destroy_list(msl_idx);
+}
+
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 {
@@ -1626,6 +1693,24 @@ eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)
        return 0;
 }
 
+int
+eal_memalloc_cleanup(void)
+{
+       /* close all remaining fd's - these are per-process, so it's safe */
+       if (rte_memseg_list_walk_thread_unsafe(fd_list_destroy_walk, NULL))
+               return -1;
+
+       /* destroy the shadow page table if we're a secondary process */
+       if (rte_eal_process_type() == RTE_PROC_PRIMARY)
+               return 0;
+
+       if (rte_memseg_list_walk_thread_unsafe(secondary_msl_destroy_walk,
+                       NULL))
+               return -1;
+
+       return 0;
+}
+
 int
 eal_memalloc_init(void)
 {
index 1e5f6576f046e88c21c1e7db0684f55c1520299a..2fc3d6141cb1c86a3a2f8c74af3864b8db9ca749 100644 (file)
@@ -251,7 +251,8 @@ rte_eal_cleanup(void)
 {
        struct internal_config *internal_conf =
                eal_get_internal_configuration();
-
+       /* after this point, any DPDK pointers will become dangling */
+       rte_eal_memory_detach();
        eal_cleanup_config(internal_conf);
        return 0;
 }
index d8cae3ebc1cc4545988fb68e4b526931b25b100a..85a9712cead468b0edee2b721f7fbaa280487b0b 100644 (file)
@@ -437,6 +437,13 @@ eal_memalloc_sync_with_primary(void)
        return -1;
 }
 
+int
+eal_memalloc_cleanup(void)
+{
+       /* not implemented */
+       return 0;
+}
+
 int
 eal_memalloc_init(void)
 {