diff --git a/lib/librte_eal/linuxapp/eal/eal_memalloc.c b/lib/librte_eal/linuxapp/eal/eal_memalloc.c
index 220daef290..8c11f98c92 100644
--- a/lib/librte_eal/linuxapp/eal/eal_memalloc.c
+++ b/lib/librte_eal/linuxapp/eal/eal_memalloc.c
@@ -610,14 +610,6 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 	/* erase page data */
 	memset(ms->addr, 0, ms->len);
 
-	/* if we are not in single file segments mode, we're going to unmap the
-	 * segment and thus drop the lock on original fd, so take out another
-	 * shared lock before we do that.
-	 */
-	fd = get_seg_fd(path, sizeof(path), hi, list_idx, seg_idx);
-	if (fd < 0)
-		return -1;
-
 	if (mmap(ms->addr, ms->len, PROT_READ,
 			MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) ==
 				MAP_FAILED) {
@@ -625,6 +617,14 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		return -1;
 	}
 
+	/* if we are not in single file segments mode, we're going to unmap the
+	 * segment and thus drop the lock on original fd, but hugepage dir is
+	 * now locked so we can take out another one without races.
+	 */
+	fd = get_seg_fd(path, sizeof(path), hi, list_idx, seg_idx);
+	if (fd < 0)
+		return -1;
+
 	if (internal_config.single_file_segments) {
 		map_offset = seg_idx * ms->len;
 		if (resize_hugefile(fd, path, list_idx, seg_idx, map_offset,
@@ -735,12 +735,13 @@ alloc_seg_walk(const struct rte_memseg_list *msl, void *arg)
 						&cur_msl->memseg_arr;
 
 				tmp = rte_fbarray_get(arr, j);
-				if (free_seg(tmp, wa->hi, msl_idx, j)) {
-					RTE_LOG(ERR, EAL, "Cannot free page\n");
-					continue;
-				}
-
 				rte_fbarray_set_free(arr, j);
+
+				/* free_seg may attempt to create a file, which
+				 * may fail.
+				 */
+				if (free_seg(tmp, wa->hi, msl_idx, j))
+					RTE_LOG(DEBUG, EAL, "Cannot free page\n");
 			}
 			/* clear the list */
 			if (wa->ms)