mem: fix potential bad unmap on map failure
[dpdk.git] / lib / librte_eal / linuxapp / eal / eal_memalloc.c
index 8063fe3..559e3f2 100644 (file)
@@ -146,7 +146,7 @@ resotre_numa(int *oldpolicy, struct bitmask *oldmask)
 {
        RTE_LOG(DEBUG, EAL,
                "Restoring previous memory policy: %d\n", *oldpolicy);
-       if (oldpolicy == MPOL_DEFAULT) {
+       if (*oldpolicy == MPOL_DEFAULT) {
                numa_set_localalloc();
        } else if (set_mempolicy(*oldpolicy, oldmask->maskp,
                                 oldmask->size + 1) < 0) {
@@ -419,7 +419,7 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
        if (internal_config.single_file_segments) {
                map_offset = seg_idx * alloc_sz;
                ret = resize_hugefile(fd, map_offset, alloc_sz, true);
-               if (ret < 1)
+               if (ret < 0)
                        goto resized;
        } else {
                map_offset = 0;
@@ -458,9 +458,6 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
         */
        void *va = mmap(addr, alloc_sz, PROT_READ | PROT_WRITE,
                        MAP_SHARED | MAP_POPULATE | MAP_FIXED, fd, map_offset);
-       /* for non-single file segments, we can close fd here */
-       if (!internal_config.single_file_segments)
-               close(fd);
 
        if (va == MAP_FAILED) {
                RTE_LOG(DEBUG, EAL, "%s(): mmap() failed: %s\n", __func__,
@@ -469,7 +466,8 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
        }
        if (va != addr) {
                RTE_LOG(DEBUG, EAL, "%s(): wrong mmap() address\n", __func__);
-               goto mapped;
+               munmap(va, alloc_sz);
+               goto resized;
        }
 
        rte_iova_t iova = rte_mem_virt2iova(addr);
@@ -502,6 +500,10 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
                        (unsigned int)(alloc_sz >> 20));
                goto mapped;
        }
+       /* for non-single file segments, we can close fd here */
+       if (!internal_config.single_file_segments)
+               close(fd);
+
        *(int *)addr = *(int *)addr;
 
        ms->addr = addr;
@@ -521,13 +523,14 @@ resized:
                resize_hugefile(fd, map_offset, alloc_sz, false);
                if (is_zero_length(fd)) {
                        struct msl_entry *te = get_msl_entry_by_idx(list_idx);
-                       if (te != NULL && te->fd >= 0) {
-                               close(te->fd);
+                       /* te->fd is equivalent to fd */
+                       if (te != NULL && te->fd >= 0)
                                te->fd = -1;
-                       }
                        /* ignore errors, can't make it any worse */
                        unlink(path);
+                       close(fd);
                }
+               /* if we're not removing the file, fd stays in the tailq */
        } else {
                close(fd);
                unlink(path);
@@ -566,12 +569,13 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
                 */
                if (is_zero_length(fd)) {
                        struct msl_entry *te = get_msl_entry_by_idx(list_idx);
-                       if (te != NULL && te->fd >= 0) {
-                               close(te->fd);
+                       /* te->fd is equivalent to fd */
+                       if (te != NULL && te->fd >= 0)
                                te->fd = -1;
-                       }
                        unlink(path);
+                       close(fd);
                }
+               /* if we're not removing the file, fd stays in the tailq */
                ret = 0;
        } else {
                /* if we're able to take out a write lock, we're the last one
@@ -807,6 +811,13 @@ eal_memalloc_free_seg_bulk(struct rte_memseg **ms, int n_segs)
                struct free_walk_param wa;
                int i, walk_res;
 
+               /* if this page is marked as unfreeable, fail */
+               if (cur->flags & RTE_MEMSEG_FLAG_DO_NOT_FREE) {
+                       RTE_LOG(DEBUG, EAL, "Page is not allowed to be freed\n");
+                       ret = -1;
+                       continue;
+               }
+
                memset(&wa, 0, sizeof(wa));
 
                for (i = 0; i < (int)RTE_DIM(internal_config.hugepage_info);