Skip to contentSkip to conversation

Improve running DPDK without hugetlbfs mounpoint

PATCH Superseded Anatoly Burakov 4 participants 45 messages Aug 23, 2018 – Sep 19, 2018

lore
Share & tools
lore
#0 lore raw

cover Improve running DPDK without hugetlbfs mounpoint

This patchset further improves DPDK support for running without hugetlbfs mountpoints.

First of all, it enables using memfd-created hugepages in in-memory mode. This way, instead of anonymous hugepages, we can get proper fd's for each page (or for the entire segment, if we're using single-file segments). Memfd will be used automatically if support for it was compiled and is available at runtime, however DPDK will fall back to using anonymous hugepages if such support is not available.

The other thing this patchset does is exposing segment fd's through an external API. There is a lot of ugliness in current virtio/vhost code that deals with finding hugepage files through procfs, while all virtio really needs are fd's referring to the pages. Using this API, virtio will be able to access segment fd's directly, without the procfs magic.

As a bonus, because we enabled use of memfd (given that sufficiently recent kernel version is used), once virtio support for getting segment fd's using the new API is implemented, virtio will also be able to work without having hugetlbfs mountpoints.

Virtio support is not provided in this patchset, coordination and implementation of it is up to virtio maintainers.

Once virtio support for this is in place, DPDK will have one less barrier for adoption in container space.

Anatoly Burakov (8):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: support using memfd segments for in-memory mode

 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  12 +
 lib/librte_eal/common/eal_common_fbarray.c |   4 +
 lib/librte_eal/common/eal_common_memory.c  |  55 ++-
 lib/librte_eal/common/eal_common_options.c |  12 +-
 lib/librte_eal/common/eal_memalloc.h       |   6 +
 lib/librte_eal/common/include/rte_memory.h |  44 +++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 421 ++++++++++++++++-----
 lib/librte_eal/linuxapp/eal/eal_memory.c   |  60 ++-
 lib/librte_eal/rte_eal_version.map         |   2 +
 9 files changed, 518 insertions(+), 98 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/8 fbarray: fix detach in noshconf mode

In noshconf mode, no shared files are created, but we're still trying to unlink them, resulting in detach/destroy failure even though it should have succeeded. Fix it by exiting early in noshconf mode.

Fixes 3ee2cde248a7 ("fbarray: support --no-shconf mode")
---
 lib/librte_eal/common/eal_common_fbarray.c | 4 ++++
 1 file changed, 4 insertions(+)
lib/librte_eal/common/eal_common_fbarray.c +4 -0
index 43caf3ced..ba6c4ae39 100644
@@ -878,6 +878,10 @@ rte_fbarray_destroy(struct rte_fbarray *arr)
 	if (ret)
 		return ret;
 
+	/* with no shconf, there were never any files to begin with */
+	if (internal_config.no_shconf)
+		return 0;
+
 	/* try deleting the file */
 	eal_get_fbarray_path(path, sizeof(path), arr->name);
 
Signature · 1 line
2.17.1
#2 lore raw

PATCH 2/8 eal: don't allow legacy mode with in-memory mode

In reply to Anatoly Burakov

In-memory mode was never meant to support legacy mode, because we cannot sort anonymous pages anyway.

Fixes 72b49ff623c4 ("mem: support --in-memory mode")
---
 lib/librte_eal/common/eal_common_options.c | 6 ++++++
 1 file changed, 6 insertions(+)
lib/librte_eal/common/eal_common_options.c +6 -0
index dd5f97402..873099acc 100644
@@ -1390,6 +1390,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"--"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
+	if (internal_cfg->legacy_mem &&
+			internal_cfg->in_memory) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
+				"with --"OPT_IN_MEMORY"\n");
+		return -1;
+	}
 
 	return 0;
 }
Signature · 1 line
2.17.1
#3 lore raw

PATCH 3/8 mem: raise maximum fd limit unconditionally

In reply to Anatoly Burakov

Previously, when we allocated hugepages, we closed the fd's corresponding to them after we've done our mappings. Since we did mmap(), we didn't actually lose the reference, but file descriptors used for mmap() do not count against the fd limit. Since we are going to store all of our fd's, we will hit the fd limit much more often when using smaller page sizes.

Fix this to raise the fd limit to maximum unconditionally.

---
 lib/librte_eal/linuxapp/eal/eal_memory.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
lib/librte_eal/linuxapp/eal/eal_memory.c +20 -0
index dbf19499e..dfb537f59 100644
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <sys/queue.h>
 #include <sys/file.h>
+#include <sys/resource.h>
 #include <unistd.h>
 #include <limits.h>
 #include <sys/ioctl.h>
@@ -2204,6 +2205,25 @@ memseg_secondary_init(void)
 int
 rte_eal_memseg_init(void)
 {
+	/* increase rlimit to maximum */
+	struct rlimit lim;
+
+	if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
+		/* set limit to maximum */
+		lim.rlim_cur = lim.rlim_max;
+
+		if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files failed: %s\n",
+					strerror(errno));
+		} else {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files to %"
+					PRIu64 "\n",
+					(uint64_t)lim.rlim_cur);
+		}
+	} else {
+		RTE_LOG(ERR, EAL, "Cannot get current resource limits\n");
+	}
+
 	return rte_eal_process_type() == RTE_PROC_PRIMARY ?
 #ifndef RTE_ARCH_64
 			memseg_primary_init_32() :
Signature · 1 line
2.17.1
#4 lore raw

PATCH 4/8 memalloc: rename lock list to fd list

In reply to Anatoly Burakov

Previously, we were only using lock lists to store per-page lock fd's because we cannot use modern fcntl() file description locks to lock parts of the page in single file segments mode.

Now, we will be using this list to store either lock fd's (along with memseg list fd) in single file segments mode, or per-page fd's (and set memseg list fd to -1), so rename the list accordingly.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 66 ++++++++++++----------
 1 file changed, 37 insertions(+), 29 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +37 -29
index aa95551a8..14bc5dce9 100644
@@ -57,25 +57,33 @@ const int anonymous_hugepages_supported =
  */
 static int fallocate_supported = -1; /* unknown */
 
-/* for single-file segments, we need some kind of mechanism to keep track of
+/*
+ * we have two modes - single file segments, and file-per-page mode.
+ *
+ * for single-file segments, we need some kind of mechanism to keep track of
  * which hugepages can be freed back to the system, and which cannot. we cannot
  * use flock() because they don't allow locking parts of a file, and we cannot
  * use fcntl() due to issues with their semantics, so we will have to rely on a
- * bunch of lockfiles for each page.
+ * bunch of lockfiles for each page. so, we will use 'fds' array to keep track
+ * of per-page lockfiles. we will store the actual segment list fd in the
+ * 'memseg_list_fd' field.
+ *
+ * for file-per-page mode, each page will have its own fd, so 'memseg_list_fd'
+ * will be invalid (set to -1), and we'll use 'fds' to keep track of page fd's.
  *
  * we cannot know how many pages a system will have in advance, but we do know
  * that they come in lists, and we know lengths of these lists. so, simply store
  * a malloc'd array of fd's indexed by list and segment index.
  *
  * they will be initialized at startup, and filled as we allocate/deallocate
- * segments. also, use this to track memseg list proper fd.
+ * segments.
  */
 static struct {
 	int *fds; /**< dynamically allocated array of segment lock fd's */
 	int memseg_list_fd; /**< memseg list fd */
 	int len; /**< total length of the array */
 	int count; /**< entries used in an array */
-} lock_fds[RTE_MAX_MEMSEG_LISTS];
+} fd_list[RTE_MAX_MEMSEG_LISTS];
 
 /** local copy of a memory map, used to synchronize memory hotplug in MP */
 static struct rte_memseg_list local_memsegs[RTE_MAX_MEMSEG_LISTS];
@@ -209,12 +217,12 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 	char path[PATH_MAX] = {0};
 	int fd;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 	/* does this lock already exist? */
 	if (fd >= 0)
 		return fd;
@@ -236,8 +244,8 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 		return -1;
 	}
 	/* store it for future reference */
-	lock_fds[list_idx].fds[seg_idx] = fd;
-	lock_fds[list_idx].count++;
+	fd_list[list_idx].fds[seg_idx] = fd;
+	fd_list[list_idx].count++;
 	return fd;
 }
 
@@ -245,12 +253,12 @@ static int unlock_segment(int list_idx, int seg_idx)
 {
 	int fd, ret;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 
 	/* upgrade lock to exclusive to see if we can remove the lockfile */
 	ret = lock(fd, LOCK_EX);
@@ -270,8 +278,8 @@ static int unlock_segment(int list_idx, int seg_idx)
 	 * and remove it from list anyway.
 	 */
 	close(fd);
-	lock_fds[list_idx].fds[seg_idx] = -1;
-	lock_fds[list_idx].count--;
+	fd_list[list_idx].fds[seg_idx] = -1;
+	fd_list[list_idx].count--;
 
 	if (ret < 0)
 		return -1;
@@ -288,7 +296,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx);
 
-		fd = lock_fds[list_idx].memseg_list_fd;
+		fd = fd_list[list_idx].memseg_list_fd;
 
 		if (fd < 0) {
 			fd = open(path, O_CREAT | O_RDWR, 0600);
@@ -304,7 +312,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 				close(fd);
 				return -1;
 			}
-			lock_fds[list_idx].memseg_list_fd = fd;
+			fd_list[list_idx].memseg_list_fd = fd;
 		}
 	} else {
 		/* create a hugepage file path */
@@ -410,9 +418,9 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * page file fd, so that one of the processes
 				 * could then delete the file after shrinking.
 				 */
-				if (ret < 1 && lock_fds[list_idx].count == 0) {
+				if (ret < 1 && fd_list[list_idx].count == 0) {
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 
 				if (ret < 0) {
@@ -448,13 +456,13 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * more segments active in this segment list,
 				 * and remove the file if there aren't.
 				 */
-				if (lock_fds[list_idx].count == 0) {
+				if (fd_list[list_idx].count == 0) {
 					if (unlink(path))
 						RTE_LOG(ERR, EAL, "%s(): unlinking '%s' failed: %s\n",
 							__func__, path,
 							strerror(errno));
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 			}
 		}
@@ -1319,7 +1327,7 @@ secondary_msl_create_walk(const struct rte_memseg_list *msl,
 }
 
 static int
-secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
+fd_list_create_walk(const struct rte_memseg_list *msl,
 		void *arg __rte_unused)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
@@ -1330,20 +1338,20 @@ secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
 	msl_idx = msl - mcfg->memsegs;
 	len = msl->memseg_arr.len;
 
-	/* ensure we have space to store lock fd per each possible segment */
+	/* ensure we have space to store fd per each possible segment */
 	data = malloc(sizeof(int) * len);
 	if (data == NULL) {
-		RTE_LOG(ERR, EAL, "Unable to allocate space for lock descriptors\n");
+		RTE_LOG(ERR, EAL, "Unable to allocate space for file descriptors\n");
 		return -1;
 	}
 	/* set all fd's as invalid */
 	for (i = 0; i < len; i++)
 		data[i] = -1;
 
-	lock_fds[msl_idx].fds = data;
-	lock_fds[msl_idx].len = len;
-	lock_fds[msl_idx].count = 0;
-	lock_fds[msl_idx].memseg_list_fd = -1;
+	fd_list[msl_idx].fds = data;
+	fd_list[msl_idx].len = len;
+	fd_list[msl_idx].count = 0;
+	fd_list[msl_idx].memseg_list_fd = -1;
 
 	return 0;
 }
@@ -1355,9 +1363,9 @@ eal_memalloc_init(void)
 		if (rte_memseg_list_walk(secondary_msl_create_walk, NULL) < 0)
 			return -1;
 
-	/* initialize all of the lock fd lists */
+	/* initialize all of the fd lists */
 	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(secondary_lock_list_create_walk, NULL))
+		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
 			return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
#5 lore raw

PATCH 5/8 memalloc: track page fd's in non-single file mode

In reply to Anatoly Burakov

Previously, we were only tracking lock file fd's in single-file segments mode, but did not track fd's in non-single file mode because we didn't need to (mmap() call still kept the lock). Now that we are going to expose these fd's to the world, we need to have access to them, so track them even in non-single file segments mode.

We don't need to close fd's after mmap() because we're still tracking them in an fd list. Also, for anonymous hugepages mode, fd will always be -1 so exit early on error.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 44 ++++++++++++----------
 1 file changed, 25 insertions(+), 19 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +25 -19
index 14bc5dce9..7d536350e 100644
@@ -318,18 +318,24 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir,
 				list_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx);
-		fd = open(path, O_CREAT | O_RDWR, 0600);
+
+		fd = fd_list[list_idx].fds[seg_idx];
+
 		if (fd < 0) {
-			RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n", __func__,
-					strerror(errno));
-			return -1;
-		}
-		/* take out a read lock */
-		if (lock(fd, LOCK_SH) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
-				__func__, strerror(errno));
-			close(fd);
-			return -1;
+			fd = open(path, O_CREAT | O_RDWR, 0600);
+			if (fd < 0) {
+				RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n",
+					__func__, strerror(errno));
+				return -1;
+			}
+			/* take out a read lock */
+			if (lock(fd, LOCK_SH) < 0) {
+				RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
+					__func__, strerror(errno));
+				close(fd);
+				return -1;
+			}
+			fd_list[list_idx].fds[seg_idx] = fd;
 		}
 	}
 	return fd;
@@ -601,10 +607,6 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		goto mapped;
 	}
 #endif
-	/* for non-single file segments that aren't in-memory, we can close fd
-	 * here */
-	if (!internal_config.single_file_segments && !internal_config.in_memory)
-		close(fd);
 
 	ms->addr = addr;
 	ms->hugepage_sz = alloc_sz;
@@ -634,7 +636,10 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		RTE_LOG(CRIT, EAL, "Can't mmap holes in our virtual address space\n");
 	}
 resized:
-	/* in-memory mode will never be single-file-segments mode */
+	/* some codepaths will return negative fd, so exit early */
+	if (fd < 0)
+		return -1;
+
 	if (internal_config.single_file_segments) {
 		resize_hugefile(fd, path, list_idx, seg_idx, map_offset,
 				alloc_sz, false);
@@ -646,6 +651,7 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 	return -1;
 }
@@ -700,6 +706,7 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		}
 		/* closing fd will drop the lock */
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 
 	memset(ms, 0, sizeof(*ms));
@@ -1364,8 +1371,7 @@ eal_memalloc_init(void)
 			return -1;
 
 	/* initialize all of the fd lists */
-	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
-			return -1;
+	if (rte_memseg_list_walk(fd_list_create_walk, NULL))
+		return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
#6 lore raw

PATCH 6/8 memalloc: add EAL-internal API to get and set segment fd's

In reply to Anatoly Burakov

Enable setting and retrieving segment fd's internally.

For now, retrieving fd's will not be used anywhere until we get an external API, but it will be useful for things like virtio, where we wish to share segment fd's.

Setting segment fd's will not be available as a public API at this time, but internally it is needed for legacy mode, because we're not allocating our hugepages in memalloc in legacy mode case, and we still need to store the fd.

Another user of get segment fd API is memseg info dump, to show which pages use which fd's.

Not supported on FreeBSD.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   | 12 +++++
 lib/librte_eal/common/eal_common_memory.c  |  8 +--
 lib/librte_eal/common/eal_memalloc.h       |  6 +++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 60 +++++++++++++++++-----
 lib/librte_eal/linuxapp/eal/eal_memory.c   | 40 ++++++++++++---
 5 files changed, 105 insertions(+), 21 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +12 -0
index f7f07abd6..a5fb09f71 100644
@@ -47,6 +47,18 @@ eal_memalloc_sync_with_primary(void)
 	return -1;
 }
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
+{
+	return -1;
+}
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
+{
+	return -1;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/common/eal_common_memory.c +5 -3
index fbfb1b055..034c2026a 100644
@@ -294,7 +294,7 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 		void *arg)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
-	int msl_idx, ms_idx;
+	int msl_idx, ms_idx, fd;
 	FILE *f = arg;
 
 	msl_idx = msl - mcfg->memsegs;
@@ -305,10 +305,11 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 	if (ms_idx < 0)
 		return -1;
 
+	fd = eal_memalloc_get_seg_fd(msl_idx, ms_idx);
 	fprintf(f, "Segment %i-%i: IOVA:0x%"PRIx64", len:%zu, "
 			"virt:%p, socket_id:%"PRId32", "
 			"hugepage_sz:%"PRIu64", nchannel:%"PRIx32", "
-			"nrank:%"PRIx32"\n",
+			"nrank:%"PRIx32" fd:%i\n",
 			msl_idx, ms_idx,
 			ms->iova,
 			ms->len,
@@ -316,7 +317,8 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 			ms->socket_id,
 			ms->hugepage_sz,
 			ms->nchannel,
-			ms->nrank);
+			ms->nrank,
+			fd);
 
 	return 0;
 }
lib/librte_eal/common/eal_memalloc.h +6 -0
index 36bb1a027..a46c69c72 100644
@@ -76,6 +76,12 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
 int
 eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
+
 int
 eal_memalloc_init(void);
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +48 -12

78 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +34 -6
index dfb537f59..ace14c877 100644
@@ -772,7 +772,8 @@ remap_segment(struct hugepage_file *hugepages, int seg_start, int seg_end)
 
 		rte_fbarray_set_used(arr, ms_idx);
 
-		close(fd);
+		/* store segment fd internally */
+		eal_memalloc_set_seg_fd(msl_idx, ms_idx, fd);
 	}
 	RTE_LOG(DEBUG, EAL, "Allocated %" PRIu64 "M on socket %i\n",
 			(seg_len * page_sz) >> 20, socket_id);
@@ -1771,6 +1772,7 @@ getFileSize(int fd)
 static int
 eal_legacy_hugepage_attach(void)
 {
+	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
 	struct hugepage_file *hp = NULL;
 	unsigned int num_hp = 0;
 	unsigned int i = 0;
@@ -1814,6 +1816,9 @@ eal_legacy_hugepage_attach(void)
 		struct hugepage_file *hf = &hp[i];
 		size_t map_sz = hf->size;
 		void *map_addr = hf->final_va;
+		int msl_idx, ms_idx;
+		struct rte_memseg_list *msl;
+		struct rte_memseg *ms;
 
 		/* if size is zero, no more pages left */
 		if (map_sz == 0)
@@ -1831,25 +1836,48 @@ eal_legacy_hugepage_attach(void)
 		if (map_addr == MAP_FAILED) {
 			RTE_LOG(ERR, EAL, "Could not map %s: %s\n",
 				hf->filepath, strerror(errno));
-			close(fd);
-			goto error;
+			goto fd_error;
 		}
 
 		/* set shared lock on the file. */
 		if (flock(fd, LOCK_SH) < 0) {
 			RTE_LOG(DEBUG, EAL, "%s(): Locking file failed: %s\n",
 				__func__, strerror(errno));
-			close(fd);
-			goto error;
+			goto fd_error;
 		}
 
-		close(fd);
+		/* find segment data */
+		msl = rte_mem_virt2memseg_list(map_addr);
+		if (msl == NULL) {
+			RTE_LOG(DEBUG, EAL, "%s(): Cannot find memseg list\n",
+				__func__);
+			goto fd_error;
+		}
+		ms = rte_mem_virt2memseg(map_addr, msl);
+		if (ms == NULL) {
+			RTE_LOG(DEBUG, EAL, "%s(): Cannot find memseg\n",
+				__func__);
+			goto fd_error;
+		}
+
+		msl_idx = msl - mcfg->memsegs;
+		ms_idx = rte_fbarray_find_idx(&msl->memseg_arr, ms);
+		if (ms_idx < 0) {
+			RTE_LOG(DEBUG, EAL, "%s(): Cannot find memseg idx\n",
+				__func__);
+			goto fd_error;
+		}
+
+		/* store segment fd internally */
+		eal_memalloc_set_seg_fd(msl_idx, ms_idx, fd);
 	}
 	/* unmap the hugepage config file, since we are done using it */
 	munmap(hp, size);
 	close(fd_hugepage);
 	return 0;
 
+fd_error:
+	close(fd);
 error:
 	/* map all segments into memory to make sure we get the addrs */
 	cur_seg = 0;
Signature · 1 line
2.17.1
#7 lore raw

PATCH 7/8 mem: add external API to retrieve page fd from EAL

In reply to Anatoly Burakov

Now that we can retrieve page fd's internally, we can expose it as an external API. This will add two flavors of API - thread-safe and non-thread-safe.

---
 lib/librte_eal/common/eal_common_memory.c  | 47 ++++++++++++++++++++++
 lib/librte_eal/common/include/rte_memory.h | 44 ++++++++++++++++++++
 lib/librte_eal/rte_eal_version.map         |  2 +
 3 files changed, 93 insertions(+)
lib/librte_eal/common/eal_common_memory.c +47 -0
index 034c2026a..cd3805b46 100644
@@ -550,6 +550,53 @@ rte_memseg_list_walk(rte_memseg_list_walk_t func, void *arg)
 	return ret;
 }
 
+int __rte_experimental
+rte_memseg_get_fd_thread_unsafe(const struct rte_memseg *ms)
+{
+	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+	struct rte_memseg_list *msl;
+	struct rte_fbarray *arr;
+	int msl_idx, seg_idx, fd;
+
+	if (ms == NULL) {
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	msl = rte_mem_virt2memseg_list(ms->addr);
+	if (msl == NULL) {
+		rte_errno = EINVAL;
+		return -1;
+	}
+	arr = &msl->memseg_arr;
+
+	msl_idx = msl - mcfg->memsegs;
+	seg_idx = rte_fbarray_find_idx(arr, ms);
+
+	if (!rte_fbarray_is_used(arr, seg_idx)) {
+		rte_errno = ENOENT;
+		return -1;
+	}
+
+	fd = eal_memalloc_get_seg_fd(msl_idx, seg_idx);
+	if (fd < 0)
+		rte_errno = ENOENT;
+	return fd;
+}
+
+int __rte_experimental
+rte_memseg_get_fd(const struct rte_memseg *ms)
+{
+	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+	int ret;
+
+	rte_rwlock_read_lock(&mcfg->memory_hotplug_lock);
+	ret = rte_memseg_get_fd_thread_unsafe(ms);
+	rte_rwlock_read_unlock(&mcfg->memory_hotplug_lock);
+
+	return ret;
+}
+
 /* init memory subsystem */
 int
 rte_eal_memory_init(void)
lib/librte_eal/common/include/rte_memory.h +44 -0

50 lines not on this page · raw message

lib/librte_eal/rte_eal_version.map +2 -0
index 344a43d32..e659e19d6 100644
@@ -320,6 +320,8 @@ EXPERIMENTAL {
 	rte_mem_virt2memseg_list;
 	rte_memseg_contig_walk;
 	rte_memseg_contig_walk_thread_unsafe;
+	rte_memseg_get_fd;
+	rte_memseg_get_fd_thread_unsafe;
 	rte_memseg_list_walk;
 	rte_memseg_list_walk_thread_unsafe;
 	rte_memseg_walk;
Signature · 1 line
2.17.1
#8 lore raw

PATCH 8/8 mem: support using memfd segments for in-memory mode

In reply to Anatoly Burakov

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

---
 lib/librte_eal/common/eal_common_options.c |   6 +-
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
 2 files changed, 235 insertions(+), 36 deletions(-)
lib/librte_eal/common/eal_common_options.c +3 -3
index 873099acc..ddd624110 100644
@@ -1384,10 +1384,10 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			" is only supported in non-legacy memory mode\n");
 	}
 	if (internal_cfg->single_file_segments &&
-			internal_cfg->hugepage_unlink) {
+			internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
-			"not compatible with neither --"OPT_IN_MEMORY" nor "
-			"--"OPT_HUGE_UNLINK"\n");
+			"not compatible with --"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
 	if (internal_cfg->legacy_mem &&
lib/librte_eal/linuxapp/eal/eal_memalloc.c +232 -33

349 lines not on this page · raw message

Signature · 1 line
2.17.1
#9 lore raw

Re: [PATCH 8/8] mem: support using memfd segments for in-memory mode

-----Original Message-----

Quoted 36 lines

Date: Thu, 23 Aug 2018 17:59:55 +0100
From: Anatoly Burakov <[email protected]>
To: [email protected]
CC: [email protected], [email protected], [email protected],
[email protected], [email protected]
Subject: [dpdk-dev] [PATCH 8/8] mem: support using memfd segments for
in-memory mode
X-Mailer: git-send-email 1.7.0.7

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

---
 lib/librte_eal/common/eal_common_options.c |   6 +-
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
 2 files changed, 235 insertions(+), 36 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +5 -0
+static inline uint32_t
+bsf64(uint64_t v)
+{
+       return (uint32_t)__builtin_ctzll(v);
+}

lib/librte_eal/linuxapp/eal/eal_memalloc.c get_file_size(int fd) · line 224

Quoted 10 lines
lib/librte_eal/linuxapp/eal/eal_memalloc.c +10 -0
+
+static inline uint32_t
+log2_u64(uint64_t v)
+{
+       if (v == 0)
+               return 0;
+       v = rte_align64pow2(v);
+       return bsf64(v);
+}
+

Can we move this to lib/librte_eal/common/include/rte_common.h? It has already rte_log2_u32()

#10 lore raw

Re: [PATCH 8/8] mem: support using memfd segments for in-memory mode

Quoted 42 lines · Jerin Jacob

-----Original Message-----

Quoted 41 lines

Date: Thu, 23 Aug 2018 17:59:55 +0100
From: Anatoly Burakov <[email protected]>
To: [email protected]
CC: [email protected], [email protected], [email protected],
[email protected], [email protected]
Subject: [dpdk-dev] [PATCH 8/8] mem: support using memfd segments for
in-memory mode
X-Mailer: git-send-email 1.7.0.7

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

---
  lib/librte_eal/common/eal_common_options.c |   6 +-
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
  2 files changed, 235 insertions(+), 36 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +10 -0
+static inline uint32_t
+bsf64(uint64_t v)
+{
+       return (uint32_t)__builtin_ctzll(v);
+}
+
+static inline uint32_t
+log2_u64(uint64_t v)
+{
+       if (v == 0)
Quoted 10 lines

lib/librte_eal/linuxapp/eal/eal_memalloc.c get_file_size(int fd) · line 224

Quoted 5 lines
lib/librte_eal/linuxapp/eal/eal_memalloc.c +5 -0
+               return 0;
+       v = rte_align64pow2(v);
+       return bsf64(v);
+}
+

Can we move this to lib/librte_eal/common/include/rte_common.h? It has already rte_log2_u32()

We can (and i will), unfortunately we cannot do it in this release, due to there already being an rte_bsf64 in rte_bitmap.h, and changing/renaming that API will require a deprecation notice. So, this change will be for 19.02.

Signature · 2 lines
Thanks,
Anatoly
#11 lore raw

v2 cover Improve running DPDK without hugetlbfs mounpoint

In reply to Anatoly Burakov

This patchset further improves DPDK support for running without hugetlbfs mountpoints.

First of all, it enables using memfd-created hugepages in in-memory mode. This way, instead of anonymous hugepages, we can get proper fd's for each page (or for the entire segment, if we're using single-file segments). Memfd will be used automatically if support for it was compiled and is available at runtime, however DPDK will fall back to using anonymous hugepages if such support is not available.

The other thing this patchset does is exposing segment fd's through an external API. There is a lot of ugliness in current virtio/vhost code that deals with finding hugepage files through procfs, while all virtio really needs are fd's referring to the pages, and their offsets. Using this API, virtio will be able to access segment fd's directly, without the procfs magic.

As a bonus, because we enabled use of memfd (given that sufficiently recent kernel version is used), once virtio support for getting segment fd's using the new API is implemented, virtio will also be able to work without having hugetlbfs mountpoints.

Virtio support is not provided in this patchset, coordination and implementation of it is up to virtio maintainers.

Once virtio support for this is in place, DPDK will have one less barrier for adoption in container space.

v1->v2:
- Added a new API to retrieve segment offset into its fd

Anatoly Burakov (9):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: allow querying offset into segment fd
mem: support using memfd segments for in-memory mode

 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  19 +
 lib/librte_eal/common/eal_common_fbarray.c |   4 +
 lib/librte_eal/common/eal_common_memory.c  | 107 ++++-
 lib/librte_eal/common/eal_common_options.c |  12 +-
 lib/librte_eal/common/eal_memalloc.h       |  11 +
 lib/librte_eal/common/include/rte_memory.h |  97 +++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 449 +++++++++++++++++----
 lib/librte_eal/linuxapp/eal/eal_memory.c   |  64 ++-
 lib/librte_eal/rte_eal_version.map         |   4 +
 9 files changed, 669 insertions(+), 98 deletions(-)
Signature · 1 line
2.17.1
#12 lore raw

PATCH v2 1/9 fbarray: fix detach in noshconf mode

In noshconf mode, no shared files are created, but we're still trying to unlink them, resulting in detach/destroy failure even though it should have succeeded. Fix it by exiting early in noshconf mode.

Fixes 3ee2cde248a7 ("fbarray: support --no-shconf mode")
---
 lib/librte_eal/common/eal_common_fbarray.c | 4 ++++
 1 file changed, 4 insertions(+)
lib/librte_eal/common/eal_common_fbarray.c +4 -0
index 43caf3ced..ba6c4ae39 100644
@@ -878,6 +878,10 @@ rte_fbarray_destroy(struct rte_fbarray *arr)
 	if (ret)
 		return ret;
 
+	/* with no shconf, there were never any files to begin with */
+	if (internal_config.no_shconf)
+		return 0;
+
 	/* try deleting the file */
 	eal_get_fbarray_path(path, sizeof(path), arr->name);
 
Signature · 1 line
2.17.1
#13 lore raw

PATCH v2 2/9 eal: don't allow legacy mode with in-memory mode

In reply to Anatoly Burakov

In-memory mode was never meant to support legacy mode, because we cannot sort anonymous pages anyway.

Fixes 72b49ff623c4 ("mem: support --in-memory mode")
---
 lib/librte_eal/common/eal_common_options.c | 6 ++++++
 1 file changed, 6 insertions(+)
lib/librte_eal/common/eal_common_options.c +6 -0
index dd5f97402..873099acc 100644
@@ -1390,6 +1390,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"--"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
+	if (internal_cfg->legacy_mem &&
+			internal_cfg->in_memory) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
+				"with --"OPT_IN_MEMORY"\n");
+		return -1;
+	}
 
 	return 0;
 }
Signature · 1 line
2.17.1
#14 lore raw

PATCH v2 3/9 mem: raise maximum fd limit unconditionally

In reply to Anatoly Burakov

Previously, when we allocated hugepages, we closed the fd's corresponding to them after we've done our mappings. Since we did mmap(), we didn't actually lose the reference, but file descriptors used for mmap() do not count against the fd limit. Since we are going to store all of our fd's, we will hit the fd limit much more often when using smaller page sizes.

Fix this to raise the fd limit to maximum unconditionally.

---
 lib/librte_eal/linuxapp/eal/eal_memory.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
lib/librte_eal/linuxapp/eal/eal_memory.c +20 -0
index dbf19499e..dfb537f59 100644
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <sys/queue.h>
 #include <sys/file.h>
+#include <sys/resource.h>
 #include <unistd.h>
 #include <limits.h>
 #include <sys/ioctl.h>
@@ -2204,6 +2205,25 @@ memseg_secondary_init(void)
 int
 rte_eal_memseg_init(void)
 {
+	/* increase rlimit to maximum */
+	struct rlimit lim;
+
+	if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
+		/* set limit to maximum */
+		lim.rlim_cur = lim.rlim_max;
+
+		if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files failed: %s\n",
+					strerror(errno));
+		} else {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files to %"
+					PRIu64 "\n",
+					(uint64_t)lim.rlim_cur);
+		}
+	} else {
+		RTE_LOG(ERR, EAL, "Cannot get current resource limits\n");
+	}
+
 	return rte_eal_process_type() == RTE_PROC_PRIMARY ?
 #ifndef RTE_ARCH_64
 			memseg_primary_init_32() :
Signature · 1 line
2.17.1
#15 lore raw

PATCH v2 4/9 memalloc: rename lock list to fd list

In reply to Anatoly Burakov

Previously, we were only using lock lists to store per-page lock fd's because we cannot use modern fcntl() file description locks to lock parts of the page in single file segments mode.

Now, we will be using this list to store either lock fd's (along with memseg list fd) in single file segments mode, or per-page fd's (and set memseg list fd to -1), so rename the list accordingly.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 66 ++++++++++++----------
 1 file changed, 37 insertions(+), 29 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +37 -29
index aa95551a8..14bc5dce9 100644
@@ -57,25 +57,33 @@ const int anonymous_hugepages_supported =
  */
 static int fallocate_supported = -1; /* unknown */
 
-/* for single-file segments, we need some kind of mechanism to keep track of
+/*
+ * we have two modes - single file segments, and file-per-page mode.
+ *
+ * for single-file segments, we need some kind of mechanism to keep track of
  * which hugepages can be freed back to the system, and which cannot. we cannot
  * use flock() because they don't allow locking parts of a file, and we cannot
  * use fcntl() due to issues with their semantics, so we will have to rely on a
- * bunch of lockfiles for each page.
+ * bunch of lockfiles for each page. so, we will use 'fds' array to keep track
+ * of per-page lockfiles. we will store the actual segment list fd in the
+ * 'memseg_list_fd' field.
+ *
+ * for file-per-page mode, each page will have its own fd, so 'memseg_list_fd'
+ * will be invalid (set to -1), and we'll use 'fds' to keep track of page fd's.
  *
  * we cannot know how many pages a system will have in advance, but we do know
  * that they come in lists, and we know lengths of these lists. so, simply store
  * a malloc'd array of fd's indexed by list and segment index.
  *
  * they will be initialized at startup, and filled as we allocate/deallocate
- * segments. also, use this to track memseg list proper fd.
+ * segments.
  */
 static struct {
 	int *fds; /**< dynamically allocated array of segment lock fd's */
 	int memseg_list_fd; /**< memseg list fd */
 	int len; /**< total length of the array */
 	int count; /**< entries used in an array */
-} lock_fds[RTE_MAX_MEMSEG_LISTS];
+} fd_list[RTE_MAX_MEMSEG_LISTS];
 
 /** local copy of a memory map, used to synchronize memory hotplug in MP */
 static struct rte_memseg_list local_memsegs[RTE_MAX_MEMSEG_LISTS];
@@ -209,12 +217,12 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 	char path[PATH_MAX] = {0};
 	int fd;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 	/* does this lock already exist? */
 	if (fd >= 0)
 		return fd;
@@ -236,8 +244,8 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 		return -1;
 	}
 	/* store it for future reference */
-	lock_fds[list_idx].fds[seg_idx] = fd;
-	lock_fds[list_idx].count++;
+	fd_list[list_idx].fds[seg_idx] = fd;
+	fd_list[list_idx].count++;
 	return fd;
 }
 
@@ -245,12 +253,12 @@ static int unlock_segment(int list_idx, int seg_idx)
 {
 	int fd, ret;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 
 	/* upgrade lock to exclusive to see if we can remove the lockfile */
 	ret = lock(fd, LOCK_EX);
@@ -270,8 +278,8 @@ static int unlock_segment(int list_idx, int seg_idx)
 	 * and remove it from list anyway.
 	 */
 	close(fd);
-	lock_fds[list_idx].fds[seg_idx] = -1;
-	lock_fds[list_idx].count--;
+	fd_list[list_idx].fds[seg_idx] = -1;
+	fd_list[list_idx].count--;
 
 	if (ret < 0)
 		return -1;
@@ -288,7 +296,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx);
 
-		fd = lock_fds[list_idx].memseg_list_fd;
+		fd = fd_list[list_idx].memseg_list_fd;
 
 		if (fd < 0) {
 			fd = open(path, O_CREAT | O_RDWR, 0600);
@@ -304,7 +312,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 				close(fd);
 				return -1;
 			}
-			lock_fds[list_idx].memseg_list_fd = fd;
+			fd_list[list_idx].memseg_list_fd = fd;
 		}
 	} else {
 		/* create a hugepage file path */
@@ -410,9 +418,9 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * page file fd, so that one of the processes
 				 * could then delete the file after shrinking.
 				 */
-				if (ret < 1 && lock_fds[list_idx].count == 0) {
+				if (ret < 1 && fd_list[list_idx].count == 0) {
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 
 				if (ret < 0) {
@@ -448,13 +456,13 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * more segments active in this segment list,
 				 * and remove the file if there aren't.
 				 */
-				if (lock_fds[list_idx].count == 0) {
+				if (fd_list[list_idx].count == 0) {
 					if (unlink(path))
 						RTE_LOG(ERR, EAL, "%s(): unlinking '%s' failed: %s\n",
 							__func__, path,
 							strerror(errno));
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 			}
 		}
@@ -1319,7 +1327,7 @@ secondary_msl_create_walk(const struct rte_memseg_list *msl,
 }
 
 static int
-secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
+fd_list_create_walk(const struct rte_memseg_list *msl,
 		void *arg __rte_unused)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
@@ -1330,20 +1338,20 @@ secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
 	msl_idx = msl - mcfg->memsegs;
 	len = msl->memseg_arr.len;
 
-	/* ensure we have space to store lock fd per each possible segment */
+	/* ensure we have space to store fd per each possible segment */
 	data = malloc(sizeof(int) * len);
 	if (data == NULL) {
-		RTE_LOG(ERR, EAL, "Unable to allocate space for lock descriptors\n");
+		RTE_LOG(ERR, EAL, "Unable to allocate space for file descriptors\n");
 		return -1;
 	}
 	/* set all fd's as invalid */
 	for (i = 0; i < len; i++)
 		data[i] = -1;
 
-	lock_fds[msl_idx].fds = data;
-	lock_fds[msl_idx].len = len;
-	lock_fds[msl_idx].count = 0;
-	lock_fds[msl_idx].memseg_list_fd = -1;
+	fd_list[msl_idx].fds = data;
+	fd_list[msl_idx].len = len;
+	fd_list[msl_idx].count = 0;
+	fd_list[msl_idx].memseg_list_fd = -1;
 
 	return 0;
 }
@@ -1355,9 +1363,9 @@ eal_memalloc_init(void)
 		if (rte_memseg_list_walk(secondary_msl_create_walk, NULL) < 0)
 			return -1;
 
-	/* initialize all of the lock fd lists */
+	/* initialize all of the fd lists */
 	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(secondary_lock_list_create_walk, NULL))
+		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
 			return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
#16 lore raw

PATCH v2 5/9 memalloc: track page fd's in non-single file mode

In reply to Anatoly Burakov

Previously, we were only tracking lock file fd's in single-file segments mode, but did not track fd's in non-single file mode because we didn't need to (mmap() call still kept the lock). Now that we are going to expose these fd's to the world, we need to have access to them, so track them even in non-single file segments mode.

We don't need to close fd's after mmap() because we're still tracking them in an fd list. Also, for anonymous hugepages mode, fd will always be -1 so exit early on error.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 44 ++++++++++++----------
 1 file changed, 25 insertions(+), 19 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +25 -19
index 14bc5dce9..7d536350e 100644
@@ -318,18 +318,24 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir,
 				list_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx);
-		fd = open(path, O_CREAT | O_RDWR, 0600);
+
+		fd = fd_list[list_idx].fds[seg_idx];
+
 		if (fd < 0) {
-			RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n", __func__,
-					strerror(errno));
-			return -1;
-		}
-		/* take out a read lock */
-		if (lock(fd, LOCK_SH) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
-				__func__, strerror(errno));
-			close(fd);
-			return -1;
+			fd = open(path, O_CREAT | O_RDWR, 0600);
+			if (fd < 0) {
+				RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n",
+					__func__, strerror(errno));
+				return -1;
+			}
+			/* take out a read lock */
+			if (lock(fd, LOCK_SH) < 0) {
+				RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
+					__func__, strerror(errno));
+				close(fd);
+				return -1;
+			}
+			fd_list[list_idx].fds[seg_idx] = fd;
 		}
 	}
 	return fd;
@@ -601,10 +607,6 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		goto mapped;
 	}
 #endif
-	/* for non-single file segments that aren't in-memory, we can close fd
-	 * here */
-	if (!internal_config.single_file_segments && !internal_config.in_memory)
-		close(fd);
 
 	ms->addr = addr;
 	ms->hugepage_sz = alloc_sz;
@@ -634,7 +636,10 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		RTE_LOG(CRIT, EAL, "Can't mmap holes in our virtual address space\n");
 	}
 resized:
-	/* in-memory mode will never be single-file-segments mode */
+	/* some codepaths will return negative fd, so exit early */
+	if (fd < 0)
+		return -1;
+
 	if (internal_config.single_file_segments) {
 		resize_hugefile(fd, path, list_idx, seg_idx, map_offset,
 				alloc_sz, false);
@@ -646,6 +651,7 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 	return -1;
 }
@@ -700,6 +706,7 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		}
 		/* closing fd will drop the lock */
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 
 	memset(ms, 0, sizeof(*ms));
@@ -1364,8 +1371,7 @@ eal_memalloc_init(void)
 			return -1;
 
 	/* initialize all of the fd lists */
-	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
-			return -1;
+	if (rte_memseg_list_walk(fd_list_create_walk, NULL))
+		return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
#17 lore raw

PATCH v2 6/9 memalloc: add EAL-internal API to get and set segment fd's

In reply to Anatoly Burakov

Enable setting and retrieving segment fd's internally.

For now, retrieving fd's will not be used anywhere until we get an external API, but it will be useful for things like virtio, where we wish to share segment fd's.

Setting segment fd's will not be available as a public API at this time, but internally it is needed for legacy mode, because we're not allocating our hugepages in memalloc in legacy mode case, and we still need to store the fd.

Another user of get segment fd API is memseg info dump, to show which pages use which fd's.

Not supported on FreeBSD.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   | 12 +++++
 lib/librte_eal/common/eal_common_memory.c  |  8 +--
 lib/librte_eal/common/eal_memalloc.h       |  6 +++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 60 +++++++++++++++++-----
 lib/librte_eal/linuxapp/eal/eal_memory.c   | 44 +++++++++++++---
 5 files changed, 109 insertions(+), 21 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +12 -0
index f7f07abd6..a5fb09f71 100644
@@ -47,6 +47,18 @@ eal_memalloc_sync_with_primary(void)
 	return -1;
 }
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
+{
+	return -1;
+}
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
+{
+	return -1;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/common/eal_common_memory.c +5 -3
index fbfb1b055..034c2026a 100644
@@ -294,7 +294,7 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 		void *arg)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
-	int msl_idx, ms_idx;
+	int msl_idx, ms_idx, fd;
 	FILE *f = arg;
 
 	msl_idx = msl - mcfg->memsegs;
@@ -305,10 +305,11 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 	if (ms_idx < 0)
 		return -1;
 
+	fd = eal_memalloc_get_seg_fd(msl_idx, ms_idx);
 	fprintf(f, "Segment %i-%i: IOVA:0x%"PRIx64", len:%zu, "
 			"virt:%p, socket_id:%"PRId32", "
 			"hugepage_sz:%"PRIu64", nchannel:%"PRIx32", "
-			"nrank:%"PRIx32"\n",
+			"nrank:%"PRIx32" fd:%i\n",
 			msl_idx, ms_idx,
 			ms->iova,
 			ms->len,
@@ -316,7 +317,8 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 			ms->socket_id,
 			ms->hugepage_sz,
 			ms->nchannel,
-			ms->nrank);
+			ms->nrank,
+			fd);
 
 	return 0;
 }
lib/librte_eal/common/eal_memalloc.h +6 -0
index 36bb1a027..a46c69c72 100644
@@ -76,6 +76,12 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
 int
 eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
+
 int
 eal_memalloc_init(void);
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +48 -12

78 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +38 -6

82 lines not on this page · raw message

Signature · 1 line
2.17.1
#18 lore raw

PATCH v2 7/9 mem: add external API to retrieve page fd from EAL

In reply to Anatoly Burakov

Now that we can retrieve page fd's internally, we can expose it as an external API. This will add two flavors of API - thread-safe and non-thread-safe. Fix up internal API's to return values we need without modifying rte_errno internally if called from within EAL.

We do not want calling code to accidentally close an internal fd, so we make a duplicate of it before we return it to the user. Caller is therefore responsible for closing this fd.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  5 ++-
 lib/librte_eal/common/eal_common_memory.c  | 49 ++++++++++++++++++++++
 lib/librte_eal/common/eal_memalloc.h       |  2 +
 lib/librte_eal/common/include/rte_memory.h | 48 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 21 ++++++----
 lib/librte_eal/rte_eal_version.map         |  2 +
 6 files changed, 118 insertions(+), 9 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +3 -2
index a5fb09f71..80e4c3d4f 100644
@@ -4,6 +4,7 @@
 
 #include <inttypes.h>
 
+#include <rte_errno.h>
 #include <rte_log.h>
 #include <rte_memory.h>
 
@@ -50,13 +51,13 @@ eal_memalloc_sync_with_primary(void)
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 {
-	return -1;
+	return -ENOTSUP;
 }
 
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 {
-	return -1;
+	return -ENOTSUP;
 }
 
 int
lib/librte_eal/common/eal_common_memory.c +49 -0

55 lines not on this page · raw message

lib/librte_eal/common/eal_memalloc.h +2 -0
index a46c69c72..70a214de4 100644
@@ -76,9 +76,11 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
 int
 eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
 
+/* returns fd or -errno */
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
 
+/* returns 0 or -errno */
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
 
lib/librte_eal/common/include/rte_memory.h +48 -0

54 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memalloc.c +14 -7
index b820989e9..21f842753 100644
@@ -34,6 +34,7 @@
 #include <rte_log.h>
 #include <rte_eal_memconfig.h>
 #include <rte_eal.h>
+#include <rte_errno.h>
 #include <rte_memory.h>
 #include <rte_spinlock.h>
 
@@ -1381,7 +1382,7 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 		int len = mcfg->memsegs[list_idx].memseg_arr.len;
 
 		if (alloc_list(list_idx, len) < 0)
-			return -1;
+			return -ENOMEM;
 	}
 	fd_list[list_idx].fds[seg_idx] = fd;
 
@@ -1391,12 +1392,18 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 {
-	if (internal_config.single_file_segments)
-		return fd_list[list_idx].memseg_list_fd;
-	/* list not initialized */
-	if (fd_list[list_idx].len == 0)
-		return -1;
-	return fd_list[list_idx].fds[seg_idx];
+	int fd;
+	if (internal_config.single_file_segments) {
+		fd = fd_list[list_idx].memseg_list_fd;
+	} else if (fd_list[list_idx].len == 0) {
+		/* list not initialized */
+		fd = -1;
+	} else {
+		fd = fd_list[list_idx].fds[seg_idx];
+	}
+	if (fd < 0)
+		return -ENODEV;
+	return fd;
 }
 
 int
lib/librte_eal/rte_eal_version.map +2 -0
index 344a43d32..e659e19d6 100644
@@ -320,6 +320,8 @@ EXPERIMENTAL {
 	rte_mem_virt2memseg_list;
 	rte_memseg_contig_walk;
 	rte_memseg_contig_walk_thread_unsafe;
+	rte_memseg_get_fd;
+	rte_memseg_get_fd_thread_unsafe;
 	rte_memseg_list_walk;
 	rte_memseg_list_walk_thread_unsafe;
 	rte_memseg_walk;
Signature · 1 line
2.17.1
#19 lore raw

PATCH v2 8/9 mem: allow querying offset into segment fd

In reply to Anatoly Burakov

In a few cases, user may need to query offset into fd for a particular memory segment (for example, to selectively map pages). This commit adds a new API to do that.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  6 +++
 lib/librte_eal/common/eal_common_memory.c  | 50 ++++++++++++++++++++++
 lib/librte_eal/common/eal_memalloc.h       |  3 ++
 lib/librte_eal/common/include/rte_memory.h | 49 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 21 +++++++++
 lib/librte_eal/rte_eal_version.map         |  2 +
 6 files changed, 131 insertions(+)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +6 -0
index 80e4c3d4f..06afbcc99 100644
@@ -60,6 +60,12 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 	return -ENOTSUP;
 }
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)
+{
+	return -ENOTSUP;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/common/eal_common_memory.c +50 -0

56 lines not on this page · raw message

lib/librte_eal/common/eal_memalloc.h +3 -0
index 70a214de4..af917c2f9 100644
@@ -84,6 +84,9 @@ eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset);
+
 int
 eal_memalloc_init(void);
 
lib/librte_eal/common/include/rte_memory.h +49 -0

55 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memalloc.c +21 -0
index 21f842753..66e1d87b6 100644
@@ -1406,6 +1406,27 @@ eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 	return fd;
 }
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)
+{
+	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+
+	/* fd_list not initialized? */
+	if (fd_list[list_idx].len == 0)
+		return -ENODEV;
+	/* segment not active? */
+	if (fd_list[list_idx].fds[seg_idx] < 0)
+		return -ENOENT;
+	/* for single-file segments mode, offset is seg idx times page size */
+	if (internal_config.single_file_segments) {
+		size_t pgsz = mcfg->memsegs[list_idx].page_sz;
+		*offset = pgsz * seg_idx;
+	} else {
+		*offset = 0;
+	}
+	return 0;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/rte_eal_version.map +2 -0
index e659e19d6..ba159f7cd 100644
@@ -321,7 +321,9 @@ EXPERIMENTAL {
 	rte_memseg_contig_walk;
 	rte_memseg_contig_walk_thread_unsafe;
 	rte_memseg_get_fd;
+	rte_memseg_get_fd_offset;
 	rte_memseg_get_fd_thread_unsafe;
+	rte_memseg_get_fd_offset_thread_unsafe;
 	rte_memseg_list_walk;
 	rte_memseg_list_walk_thread_unsafe;
 	rte_memseg_walk;
Signature · 1 line
2.17.1
#20 lore raw

PATCH v2 9/9 mem: support using memfd segments for in-memory mode

In reply to Anatoly Burakov

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

---
 lib/librte_eal/common/eal_common_options.c |   6 +-
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
 2 files changed, 235 insertions(+), 36 deletions(-)
lib/librte_eal/common/eal_common_options.c +3 -3
index 873099acc..ddd624110 100644
@@ -1384,10 +1384,10 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			" is only supported in non-legacy memory mode\n");
 	}
 	if (internal_cfg->single_file_segments &&
-			internal_cfg->hugepage_unlink) {
+			internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
-			"not compatible with neither --"OPT_IN_MEMORY" nor "
-			"--"OPT_HUGE_UNLINK"\n");
+			"not compatible with --"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
 	if (internal_cfg->legacy_mem &&
lib/librte_eal/linuxapp/eal/eal_memalloc.c +232 -33

349 lines not on this page · raw message

Signature · 1 line
2.17.1
#21 lore raw

v3 cover Improve running DPDK without hugetlbfs mounpoint

In reply to Anatoly Burakov

This patchset further improves DPDK support for running without hugetlbfs mountpoints.

First of all, it enables using memfd-created hugepages in in-memory mode. This way, instead of anonymous hugepages, we can get proper fd's for each page (or for the entire segment, if we're using single-file segments). Memfd will be used automatically if support for it was compiled and is available at runtime, however DPDK will fall back to using anonymous hugepages if such support is not available.

The other thing this patchset does is exposing segment fd's through an external API. There is a lot of ugliness in current virtio/vhost code that deals with finding hugepage files through procfs, while all virtio really needs are fd's referring to the pages, and their offsets. Using this API, virtio will be able to access segment fd's directly, without the procfs magic.

As a bonus, because we enabled use of memfd (given that sufficiently recent kernel version is used), once virtio support for getting segment fd's using the new API is implemented, virtio will also be able to work without having hugetlbfs mountpoints.

Virtio support is not provided in this patchset, coordination and implementation of it is up to virtio maintainers.

Once virtio support for this is in place, DPDK will have one less barrier for adoption in container space.

v2->v3:
- Fixed single file segments mode for fd offsets

v1->v2:
- Added a new API to retrieve segment offset into its fd

Anatoly Burakov (9):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: allow querying offset into segment fd
mem: support using memfd segments for in-memory mode

 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  19 +
 lib/librte_eal/common/eal_common_fbarray.c |   4 +
 lib/librte_eal/common/eal_common_memory.c  | 107 ++++-
 lib/librte_eal/common/eal_common_options.c |  12 +-
 lib/librte_eal/common/eal_memalloc.h       |  11 +
 lib/librte_eal/common/include/rte_memory.h |  97 +++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 452 +++++++++++++++++----
 lib/librte_eal/linuxapp/eal/eal_memory.c   |  64 ++-
 lib/librte_eal/rte_eal_version.map         |   4 +
 9 files changed, 672 insertions(+), 98 deletions(-)
Signature · 1 line
2.17.1
#22 lore raw

PATCH v3 1/9 fbarray: fix detach in noshconf mode

In noshconf mode, no shared files are created, but we're still trying to unlink them, resulting in detach/destroy failure even though it should have succeeded. Fix it by exiting early in noshconf mode.

Fixes 3ee2cde248a7 ("fbarray: support --no-shconf mode")
---
 lib/librte_eal/common/eal_common_fbarray.c | 4 ++++
 1 file changed, 4 insertions(+)
lib/librte_eal/common/eal_common_fbarray.c +4 -0
index 43caf3ced..ba6c4ae39 100644
@@ -878,6 +878,10 @@ rte_fbarray_destroy(struct rte_fbarray *arr)
 	if (ret)
 		return ret;
 
+	/* with no shconf, there were never any files to begin with */
+	if (internal_config.no_shconf)
+		return 0;
+
 	/* try deleting the file */
 	eal_get_fbarray_path(path, sizeof(path), arr->name);
 
Signature · 1 line
2.17.1
Reviewed-by on v3 1/9
#23 lore raw

Re: [PATCH v3 1/9] fbarray: fix detach in noshconf mode

Quoted 11 lines · Anatoly Burakov

In noshconf mode, no shared files are created, but we're still trying to unlink them, resulting in detach/destroy failure even though it should have succeeded. Fix it by exiting early in noshconf mode.

Fixes 3ee2cde248a7 ("fbarray: support --no-shconf mode")
---
  lib/librte_eal/common/eal_common_fbarray.c | 4 ++++
  1 file changed, 4 insertions(+)
#24 lore raw

PATCH v3 2/9 eal: don't allow legacy mode with in-memory mode

In reply to Anatoly Burakov

In-memory mode was never meant to support legacy mode, because we cannot sort anonymous pages anyway.

Fixes 72b49ff623c4 ("mem: support --in-memory mode")
---
 lib/librte_eal/common/eal_common_options.c | 6 ++++++
 1 file changed, 6 insertions(+)
lib/librte_eal/common/eal_common_options.c +6 -0
index dd5f97402..873099acc 100644
@@ -1390,6 +1390,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			"--"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
+	if (internal_cfg->legacy_mem &&
+			internal_cfg->in_memory) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
+				"with --"OPT_IN_MEMORY"\n");
+		return -1;
+	}
 
 	return 0;
 }
Signature · 1 line
2.17.1
Reviewed-by on v3 2/9
#25 lore raw

Re: [PATCH v3 2/9] eal: don't allow legacy mode with in-memory mode

Quoted 16 lines · Anatoly Burakov

In-memory mode was never meant to support legacy mode, because we cannot sort anonymous pages anyway.

Fixes 72b49ff623c4 ("mem: support --in-memory mode")
---
  lib/librte_eal/common/eal_common_options.c | 6 ++++++
  1 file changed, 6 insertions(+)
lib/librte_eal/common/eal_common_options.c +0 -0
index dd5f97402..873099acc 100644

lib/librte_eal/common/eal_common_options.c eal_check_common_options(struct internal_config *internal_cfg) · line 1396

Quoted 7 lines
lib/librte_eal/common/eal_common_options.c +4 -0
@@ -1390,6 +1390,12 @@ eal_check_common_options(struct internal_config *internal_cfg)
  			"--"OPT_HUGE_UNLINK"\n");
  		return -1;
  	}
+	if (internal_cfg->legacy_mem &&
+			internal_cfg->in_memory) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
+				"with --"OPT_IN_MEMORY"\n");

This is a general comment, as it is consistent with the style of the
file. I generally prefer not splitting error strings into multiple lines
even if it is longer than 80 chars, because it makes grepping for the error string more difficult.

lib/librte_eal/common/eal_common_options.c eal_check_common_options(struct internal_config *internal_cfg) · line 1401

Quoted 6 lines
lib/librte_eal/common/eal_common_options.c +2 -0
+		return -1;
+	}
 
  	return 0;
  }

Other than that:

Thanks,
Maxime

#26 lore raw

Re: [PATCH v3 2/9] eal: don't allow legacy mode with in-memory mode

Quoted 23 lines · Maxime Coquelin
Quoted 20 lines · Anatoly Burakov

In-memory mode was never meant to support legacy mode, because we cannot sort anonymous pages anyway.

Fixes 72b49ff623c4 ("mem: support --in-memory mode")

---
  lib/librte_eal/common/eal_common_options.c | 6 ++++++

  1 file changed, 6 insertions(+)
lib/librte_eal/common/eal_common_options.c +0 -0
index dd5f97402..873099acc 100644
@@ -1390,6 +1390,12 @@ eal_check_common_options(struct internal_config 
 *internal_cfg)
               "--"OPT_HUGE_UNLINK"\n");
           return -1;
       }
Quoted 8 lines

lib/librte_eal/common/eal_common_options.c eal_check_common_options(struct internal_config *internal_cfg) · line 1396

Quoted 4 lines
lib/librte_eal/common/eal_common_options.c +4 -0
+    if (internal_cfg->legacy_mem &&
+            internal_cfg->in_memory) {
+        RTE_LOG(ERR, EAL, "Option --"OPT_LEGACY_MEM" is not compatible "
+                "with --"OPT_IN_MEMORY"\n");

This is a general comment, as it is consistent with the style of the
file. I generally prefer not splitting error strings into multiple lines
even if it is longer than 80 chars, because it makes grepping for the error string more difficult.

I agree in general, however in this particular case the string is ungreppable (it is a word now!) anyway because it's split into a few pieces.

Quoted 13 lines

lib/librte_eal/common/eal_common_options.c eal_check_common_options(struct internal_config *internal_cfg) · line 1401

Quoted 6 lines
lib/librte_eal/common/eal_common_options.c +2 -0
+        return -1;
+    }
       return 0;
   }

Other than that:

Thanks,
Maxime

Signature · 2 lines
Thanks,
Anatoly
#27 lore raw

PATCH v3 3/9 mem: raise maximum fd limit unconditionally

In reply to Anatoly Burakov

Previously, when we allocated hugepages, we closed the fd's corresponding to them after we've done our mappings. Since we did mmap(), we didn't actually lose the reference, but file descriptors used for mmap() do not count against the fd limit. Since we are going to store all of our fd's, we will hit the fd limit much more often when using smaller page sizes.

Fix this to raise the fd limit to maximum unconditionally.

---
 lib/librte_eal/linuxapp/eal/eal_memory.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
lib/librte_eal/linuxapp/eal/eal_memory.c +20 -0
index dbf19499e..dfb537f59 100644
@@ -17,6 +17,7 @@
 #include <sys/stat.h>
 #include <sys/queue.h>
 #include <sys/file.h>
+#include <sys/resource.h>
 #include <unistd.h>
 #include <limits.h>
 #include <sys/ioctl.h>
@@ -2204,6 +2205,25 @@ memseg_secondary_init(void)
 int
 rte_eal_memseg_init(void)
 {
+	/* increase rlimit to maximum */
+	struct rlimit lim;
+
+	if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
+		/* set limit to maximum */
+		lim.rlim_cur = lim.rlim_max;
+
+		if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files failed: %s\n",
+					strerror(errno));
+		} else {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files to %"
+					PRIu64 "\n",
+					(uint64_t)lim.rlim_cur);
+		}
+	} else {
+		RTE_LOG(ERR, EAL, "Cannot get current resource limits\n");
+	}
+
 	return rte_eal_process_type() == RTE_PROC_PRIMARY ?
 #ifndef RTE_ARCH_64
 			memseg_primary_init_32() :
Signature · 1 line
2.17.1
Reviewed-by on v3 3/9
#28 lore raw

Re: [PATCH v3 3/9] mem: raise maximum fd limit unconditionally

Quoted 42 lines · Anatoly Burakov

Previously, when we allocated hugepages, we closed the fd's corresponding to them after we've done our mappings. Since we did mmap(), we didn't actually lose the reference, but file descriptors used for mmap() do not count against the fd limit. Since we are going to store all of our fd's, we will hit the fd limit much more often when using smaller page sizes.

Fix this to raise the fd limit to maximum unconditionally.

---
  lib/librte_eal/linuxapp/eal/eal_memory.c | 20 ++++++++++++++++++++
  1 file changed, 20 insertions(+)
lib/librte_eal/linuxapp/eal/eal_memory.c +13 -0
index dbf19499e..dfb537f59 100644
@@ -17,6 +17,7 @@
  #include <sys/stat.h>
  #include <sys/queue.h>
  #include <sys/file.h>
+#include <sys/resource.h>
  #include <unistd.h>
  #include <limits.h>
  #include <sys/ioctl.h>
@@ -2204,6 +2205,25 @@ memseg_secondary_init(void)
  int
  rte_eal_memseg_init(void)
  {
+	/* increase rlimit to maximum */
+	struct rlimit lim;
+
+	if (getrlimit(RLIMIT_NOFILE, &lim) == 0) {
+		/* set limit to maximum */
+		lim.rlim_cur = lim.rlim_max;
+
+		if (setrlimit(RLIMIT_NOFILE, &lim) < 0) {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files failed: %s\n",
+					strerror(errno));
+		} else {
+			RTE_LOG(DEBUG, EAL, "Setting maximum number of open files to %"

lib/librte_eal/linuxapp/eal/eal_memory.c memseg_secondary_init(void) · line 2229

Quoted 10 lines
lib/librte_eal/linuxapp/eal/eal_memory.c +7 -0
+					PRIu64 "\n",
+					(uint64_t)lim.rlim_cur);
+		}
+	} else {
+		RTE_LOG(ERR, EAL, "Cannot get current resource limits\n");
+	}
+
  	return rte_eal_process_type() == RTE_PROC_PRIMARY ?
  #ifndef RTE_ARCH_64
  			memseg_primary_init_32() :
#29 lore raw

PATCH v3 4/9 memalloc: rename lock list to fd list

In reply to Anatoly Burakov

Previously, we were only using lock lists to store per-page lock fd's because we cannot use modern fcntl() file description locks to lock parts of the page in single file segments mode.

Now, we will be using this list to store either lock fd's (along with memseg list fd) in single file segments mode, or per-page fd's (and set memseg list fd to -1), so rename the list accordingly.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 66 ++++++++++++----------
 1 file changed, 37 insertions(+), 29 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +37 -29
index aa95551a8..14bc5dce9 100644
@@ -57,25 +57,33 @@ const int anonymous_hugepages_supported =
  */
 static int fallocate_supported = -1; /* unknown */
 
-/* for single-file segments, we need some kind of mechanism to keep track of
+/*
+ * we have two modes - single file segments, and file-per-page mode.
+ *
+ * for single-file segments, we need some kind of mechanism to keep track of
  * which hugepages can be freed back to the system, and which cannot. we cannot
  * use flock() because they don't allow locking parts of a file, and we cannot
  * use fcntl() due to issues with their semantics, so we will have to rely on a
- * bunch of lockfiles for each page.
+ * bunch of lockfiles for each page. so, we will use 'fds' array to keep track
+ * of per-page lockfiles. we will store the actual segment list fd in the
+ * 'memseg_list_fd' field.
+ *
+ * for file-per-page mode, each page will have its own fd, so 'memseg_list_fd'
+ * will be invalid (set to -1), and we'll use 'fds' to keep track of page fd's.
  *
  * we cannot know how many pages a system will have in advance, but we do know
  * that they come in lists, and we know lengths of these lists. so, simply store
  * a malloc'd array of fd's indexed by list and segment index.
  *
  * they will be initialized at startup, and filled as we allocate/deallocate
- * segments. also, use this to track memseg list proper fd.
+ * segments.
  */
 static struct {
 	int *fds; /**< dynamically allocated array of segment lock fd's */
 	int memseg_list_fd; /**< memseg list fd */
 	int len; /**< total length of the array */
 	int count; /**< entries used in an array */
-} lock_fds[RTE_MAX_MEMSEG_LISTS];
+} fd_list[RTE_MAX_MEMSEG_LISTS];
 
 /** local copy of a memory map, used to synchronize memory hotplug in MP */
 static struct rte_memseg_list local_memsegs[RTE_MAX_MEMSEG_LISTS];
@@ -209,12 +217,12 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 	char path[PATH_MAX] = {0};
 	int fd;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 	/* does this lock already exist? */
 	if (fd >= 0)
 		return fd;
@@ -236,8 +244,8 @@ static int get_segment_lock_fd(int list_idx, int seg_idx)
 		return -1;
 	}
 	/* store it for future reference */
-	lock_fds[list_idx].fds[seg_idx] = fd;
-	lock_fds[list_idx].count++;
+	fd_list[list_idx].fds[seg_idx] = fd;
+	fd_list[list_idx].count++;
 	return fd;
 }
 
@@ -245,12 +253,12 @@ static int unlock_segment(int list_idx, int seg_idx)
 {
 	int fd, ret;
 
-	if (list_idx < 0 || list_idx >= (int)RTE_DIM(lock_fds))
+	if (list_idx < 0 || list_idx >= (int)RTE_DIM(fd_list))
 		return -1;
-	if (seg_idx < 0 || seg_idx >= lock_fds[list_idx].len)
+	if (seg_idx < 0 || seg_idx >= fd_list[list_idx].len)
 		return -1;
 
-	fd = lock_fds[list_idx].fds[seg_idx];
+	fd = fd_list[list_idx].fds[seg_idx];
 
 	/* upgrade lock to exclusive to see if we can remove the lockfile */
 	ret = lock(fd, LOCK_EX);
@@ -270,8 +278,8 @@ static int unlock_segment(int list_idx, int seg_idx)
 	 * and remove it from list anyway.
 	 */
 	close(fd);
-	lock_fds[list_idx].fds[seg_idx] = -1;
-	lock_fds[list_idx].count--;
+	fd_list[list_idx].fds[seg_idx] = -1;
+	fd_list[list_idx].count--;
 
 	if (ret < 0)
 		return -1;
@@ -288,7 +296,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir, list_idx);
 
-		fd = lock_fds[list_idx].memseg_list_fd;
+		fd = fd_list[list_idx].memseg_list_fd;
 
 		if (fd < 0) {
 			fd = open(path, O_CREAT | O_RDWR, 0600);
@@ -304,7 +312,7 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 				close(fd);
 				return -1;
 			}
-			lock_fds[list_idx].memseg_list_fd = fd;
+			fd_list[list_idx].memseg_list_fd = fd;
 		}
 	} else {
 		/* create a hugepage file path */
@@ -410,9 +418,9 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * page file fd, so that one of the processes
 				 * could then delete the file after shrinking.
 				 */
-				if (ret < 1 && lock_fds[list_idx].count == 0) {
+				if (ret < 1 && fd_list[list_idx].count == 0) {
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 
 				if (ret < 0) {
@@ -448,13 +456,13 @@ resize_hugefile(int fd, char *path, int list_idx, int seg_idx,
 				 * more segments active in this segment list,
 				 * and remove the file if there aren't.
 				 */
-				if (lock_fds[list_idx].count == 0) {
+				if (fd_list[list_idx].count == 0) {
 					if (unlink(path))
 						RTE_LOG(ERR, EAL, "%s(): unlinking '%s' failed: %s\n",
 							__func__, path,
 							strerror(errno));
 					close(fd);
-					lock_fds[list_idx].memseg_list_fd = -1;
+					fd_list[list_idx].memseg_list_fd = -1;
 				}
 			}
 		}
@@ -1319,7 +1327,7 @@ secondary_msl_create_walk(const struct rte_memseg_list *msl,
 }
 
 static int
-secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
+fd_list_create_walk(const struct rte_memseg_list *msl,
 		void *arg __rte_unused)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
@@ -1330,20 +1338,20 @@ secondary_lock_list_create_walk(const struct rte_memseg_list *msl,
 	msl_idx = msl - mcfg->memsegs;
 	len = msl->memseg_arr.len;
 
-	/* ensure we have space to store lock fd per each possible segment */
+	/* ensure we have space to store fd per each possible segment */
 	data = malloc(sizeof(int) * len);
 	if (data == NULL) {
-		RTE_LOG(ERR, EAL, "Unable to allocate space for lock descriptors\n");
+		RTE_LOG(ERR, EAL, "Unable to allocate space for file descriptors\n");
 		return -1;
 	}
 	/* set all fd's as invalid */
 	for (i = 0; i < len; i++)
 		data[i] = -1;
 
-	lock_fds[msl_idx].fds = data;
-	lock_fds[msl_idx].len = len;
-	lock_fds[msl_idx].count = 0;
-	lock_fds[msl_idx].memseg_list_fd = -1;
+	fd_list[msl_idx].fds = data;
+	fd_list[msl_idx].len = len;
+	fd_list[msl_idx].count = 0;
+	fd_list[msl_idx].memseg_list_fd = -1;
 
 	return 0;
 }
@@ -1355,9 +1363,9 @@ eal_memalloc_init(void)
 		if (rte_memseg_list_walk(secondary_msl_create_walk, NULL) < 0)
 			return -1;
 
-	/* initialize all of the lock fd lists */
+	/* initialize all of the fd lists */
 	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(secondary_lock_list_create_walk, NULL))
+		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
 			return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
Reviewed-by on v3 4/9
#30 lore raw

Re: [PATCH v3 4/9] memalloc: rename lock list to fd list

Quoted 4 lines · Anatoly Burakov

Previously, we were only using lock lists to store per-page lock fd's because we cannot use modern fcntl() file description locks to lock parts of the page in single file segments mode.

Quoted 9 lines

Now, we will be using this list to store either lock fd's (along with memseg list fd) in single file segments mode, or per-page fd's (and set memseg list fd to -1), so rename the list accordingly.

---
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 66 ++++++++++++----------
  1 file changed, 37 insertions(+), 29 deletions(-)
#31 lore raw

PATCH v3 5/9 memalloc: track page fd's in non-single file mode

In reply to Anatoly Burakov

Previously, we were only tracking lock file fd's in single-file segments mode, but did not track fd's in non-single file mode because we didn't need to (mmap() call still kept the lock). Now that we are going to expose these fd's to the world, we need to have access to them, so track them even in non-single file segments mode.

We don't need to close fd's after mmap() because we're still tracking them in an fd list. Also, for anonymous hugepages mode, fd will always be -1 so exit early on error.

---
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 44 ++++++++++++----------
 1 file changed, 25 insertions(+), 19 deletions(-)
lib/librte_eal/linuxapp/eal/eal_memalloc.c +25 -19
index 14bc5dce9..7d536350e 100644
@@ -318,18 +318,24 @@ get_seg_fd(char *path, int buflen, struct hugepage_info *hi,
 		/* create a hugepage file path */
 		eal_get_hugefile_path(path, buflen, hi->hugedir,
 				list_idx * RTE_MAX_MEMSEG_PER_LIST + seg_idx);
-		fd = open(path, O_CREAT | O_RDWR, 0600);
+
+		fd = fd_list[list_idx].fds[seg_idx];
+
 		if (fd < 0) {
-			RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n", __func__,
-					strerror(errno));
-			return -1;
-		}
-		/* take out a read lock */
-		if (lock(fd, LOCK_SH) < 0) {
-			RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
-				__func__, strerror(errno));
-			close(fd);
-			return -1;
+			fd = open(path, O_CREAT | O_RDWR, 0600);
+			if (fd < 0) {
+				RTE_LOG(DEBUG, EAL, "%s(): open failed: %s\n",
+					__func__, strerror(errno));
+				return -1;
+			}
+			/* take out a read lock */
+			if (lock(fd, LOCK_SH) < 0) {
+				RTE_LOG(ERR, EAL, "%s(): lock failed: %s\n",
+					__func__, strerror(errno));
+				close(fd);
+				return -1;
+			}
+			fd_list[list_idx].fds[seg_idx] = fd;
 		}
 	}
 	return fd;
@@ -601,10 +607,6 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		goto mapped;
 	}
 #endif
-	/* for non-single file segments that aren't in-memory, we can close fd
-	 * here */
-	if (!internal_config.single_file_segments && !internal_config.in_memory)
-		close(fd);
 
 	ms->addr = addr;
 	ms->hugepage_sz = alloc_sz;
@@ -634,7 +636,10 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		RTE_LOG(CRIT, EAL, "Can't mmap holes in our virtual address space\n");
 	}
 resized:
-	/* in-memory mode will never be single-file-segments mode */
+	/* some codepaths will return negative fd, so exit early */
+	if (fd < 0)
+		return -1;
+
 	if (internal_config.single_file_segments) {
 		resize_hugefile(fd, path, list_idx, seg_idx, map_offset,
 				alloc_sz, false);
@@ -646,6 +651,7 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 	return -1;
 }
@@ -700,6 +706,7 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		}
 		/* closing fd will drop the lock */
 		close(fd);
+		fd_list[list_idx].fds[seg_idx] = -1;
 	}
 
 	memset(ms, 0, sizeof(*ms));
@@ -1364,8 +1371,7 @@ eal_memalloc_init(void)
 			return -1;
 
 	/* initialize all of the fd lists */
-	if (internal_config.single_file_segments)
-		if (rte_memseg_list_walk(fd_list_create_walk, NULL))
-			return -1;
+	if (rte_memseg_list_walk(fd_list_create_walk, NULL))
+		return -1;
 	return 0;
 }
Signature · 1 line
2.17.1
Reviewed-by on v3 5/9
#32 lore raw

Re: [PATCH v3 5/9] memalloc: track page fd's in non-single file mode

Quoted 7 lines · Anatoly Burakov

Previously, we were only tracking lock file fd's in single-file segments mode, but did not track fd's in non-single file mode because we didn't need to (mmap() call still kept the lock). Now that we are going to expose these fd's to the world, we need to have access to them, so track them even in non-single file segments mode.

Quoted 9 lines

We don't need to close fd's after mmap() because we're still tracking them in an fd list. Also, for anonymous hugepages mode, fd will always be -1 so exit early on error.

---
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 44 ++++++++++++----------
  1 file changed, 25 insertions(+), 19 deletions(-)
#33 lore raw

PATCH v3 6/9 memalloc: add EAL-internal API to get and set segment fd's

In reply to Anatoly Burakov

Enable setting and retrieving segment fd's internally.

For now, retrieving fd's will not be used anywhere until we get an external API, but it will be useful for things like virtio, where we wish to share segment fd's.

Setting segment fd's will not be available as a public API at this time, but internally it is needed for legacy mode, because we're not allocating our hugepages in memalloc in legacy mode case, and we still need to store the fd.

Another user of get segment fd API is memseg info dump, to show which pages use which fd's.

Not supported on FreeBSD.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   | 12 +++++
 lib/librte_eal/common/eal_common_memory.c  |  8 +--
 lib/librte_eal/common/eal_memalloc.h       |  6 +++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 60 +++++++++++++++++-----
 lib/librte_eal/linuxapp/eal/eal_memory.c   | 44 +++++++++++++---
 5 files changed, 109 insertions(+), 21 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +12 -0
index f7f07abd6..a5fb09f71 100644
@@ -47,6 +47,18 @@ eal_memalloc_sync_with_primary(void)
 	return -1;
 }
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
+{
+	return -1;
+}
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
+{
+	return -1;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/common/eal_common_memory.c +5 -3
index fbfb1b055..034c2026a 100644
@@ -294,7 +294,7 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 		void *arg)
 {
 	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
-	int msl_idx, ms_idx;
+	int msl_idx, ms_idx, fd;
 	FILE *f = arg;
 
 	msl_idx = msl - mcfg->memsegs;
@@ -305,10 +305,11 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 	if (ms_idx < 0)
 		return -1;
 
+	fd = eal_memalloc_get_seg_fd(msl_idx, ms_idx);
 	fprintf(f, "Segment %i-%i: IOVA:0x%"PRIx64", len:%zu, "
 			"virt:%p, socket_id:%"PRId32", "
 			"hugepage_sz:%"PRIu64", nchannel:%"PRIx32", "
-			"nrank:%"PRIx32"\n",
+			"nrank:%"PRIx32" fd:%i\n",
 			msl_idx, ms_idx,
 			ms->iova,
 			ms->len,
@@ -316,7 +317,8 @@ dump_memseg(const struct rte_memseg_list *msl, const struct rte_memseg *ms,
 			ms->socket_id,
 			ms->hugepage_sz,
 			ms->nchannel,
-			ms->nrank);
+			ms->nrank,
+			fd);
 
 	return 0;
 }
lib/librte_eal/common/eal_memalloc.h +6 -0
index 36bb1a027..a46c69c72 100644
@@ -76,6 +76,12 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
 int
 eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
+
 int
 eal_memalloc_init(void);
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +48 -12

78 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memory.c +38 -6

82 lines not on this page · raw message

Signature · 1 line
2.17.1
#34 lore raw

Re: [PATCH v3 6/9] memalloc: add EAL-internal API to get and set segment fd's

Quoted 30 lines · Anatoly Burakov

Enable setting and retrieving segment fd's internally.

For now, retrieving fd's will not be used anywhere until we get an external API, but it will be useful for things like virtio, where we wish to share segment fd's.

Setting segment fd's will not be available as a public API at this time, but internally it is needed for legacy mode, because we're not allocating our hugepages in memalloc in legacy mode case, and we still need to store the fd.

Another user of get segment fd API is memseg info dump, to show which pages use which fd's.

Not supported on FreeBSD.

---
  lib/librte_eal/bsdapp/eal/eal_memalloc.c   | 12 +++++
  lib/librte_eal/common/eal_common_memory.c  |  8 +--
  lib/librte_eal/common/eal_memalloc.h       |  6 +++
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 60 +++++++++++++++++-----
  lib/librte_eal/linuxapp/eal/eal_memory.c   | 44 +++++++++++++---
  5 files changed, 109 insertions(+), 21 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +0 -0
index f7f07abd6..a5fb09f71 100644

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 53

Quoted 7 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +4 -0
@@ -47,6 +47,18 @@ eal_memalloc_sync_with_primary(void)
  	return -1;
  }
 
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
+{
+	return -1;

Why not returning -ENOTSUPP directly here? (see patch 7).

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 59

Quoted 6 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +6 -0
+}
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
+{
+	return -1;

Ditto.

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 61

Quoted 2 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +2 -0
+}
+

Other than that, the patch looks good to me.

Maxime

#35 lore raw

Re: [PATCH v3 6/9] memalloc: add EAL-internal API to get and set segment fd's

Quoted 51 lines · Maxime Coquelin
Quoted 30 lines · Anatoly Burakov

Enable setting and retrieving segment fd's internally.

For now, retrieving fd's will not be used anywhere until we get an external API, but it will be useful for things like virtio, where we wish to share segment fd's.

Setting segment fd's will not be available as a public API at this time, but internally it is needed for legacy mode, because we're not allocating our hugepages in memalloc in legacy mode case, and we still need to store the fd.

Another user of get segment fd API is memseg info dump, to show which pages use which fd's.

Not supported on FreeBSD.

---
  lib/librte_eal/bsdapp/eal/eal_memalloc.c   | 12 +++++ lib/librte_eal/common/eal_common_memory.c  |  8 +-- lib/librte_eal/common/eal_memalloc.h       |  6 +++ lib/librte_eal/linuxapp/eal/eal_memalloc.c | 60 +++++++++++++++++----- lib/librte_eal/linuxapp/eal/eal_memory.c   | 44 +++++++++++++---

  5 files changed, 109 insertions(+), 21 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +0 -0
index f7f07abd6..a5fb09f71 100644

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 52

Quoted 6 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +4 -0
@@ -47,6 +47,18 @@ eal_memalloc_sync_with_primary(void)
       return -1;
   }
+int
+eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
+{
+    return -1;

Why not returning -ENOTSUPP directly here? (see patch 7).

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 59

Quoted 6 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +6 -0
+}
+
+int
+eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
+{
+    return -1;

Ditto.

Quoted 7 lines

lib/librte_eal/bsdapp/eal/eal_memalloc.c eal_memalloc_sync_with_primary(void) · line 60

Quoted 2 lines
lib/librte_eal/bsdapp/eal/eal_memalloc.c +2 -0
+}
+

Other than that, the patch looks good to me.

Maxime

Mainly for consistency reasons. Returning errno values but not using them looks weird to me, but i can change this to return those at the outset.

Signature · 2 lines
Thanks,
Anatoly
#36 lore raw

PATCH v3 7/9 mem: add external API to retrieve page fd from EAL

In reply to Anatoly Burakov

Now that we can retrieve page fd's internally, we can expose it as an external API. This will add two flavors of API - thread-safe and non-thread-safe. Fix up internal API's to return values we need without modifying rte_errno internally if called from within EAL.

We do not want calling code to accidentally close an internal fd, so we make a duplicate of it before we return it to the user. Caller is therefore responsible for closing this fd.

---
 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  5 ++-
 lib/librte_eal/common/eal_common_memory.c  | 49 ++++++++++++++++++++++
 lib/librte_eal/common/eal_memalloc.h       |  2 +
 lib/librte_eal/common/include/rte_memory.h | 48 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 21 ++++++----
 lib/librte_eal/rte_eal_version.map         |  2 +
 6 files changed, 118 insertions(+), 9 deletions(-)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +3 -2
index a5fb09f71..80e4c3d4f 100644
@@ -4,6 +4,7 @@
 
 #include <inttypes.h>
 
+#include <rte_errno.h>
 #include <rte_log.h>
 #include <rte_memory.h>
 
@@ -50,13 +51,13 @@ eal_memalloc_sync_with_primary(void)
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 {
-	return -1;
+	return -ENOTSUP;
 }
 
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 {
-	return -1;
+	return -ENOTSUP;
 }
 
 int
lib/librte_eal/common/eal_common_memory.c +49 -0

55 lines not on this page · raw message

lib/librte_eal/common/eal_memalloc.h +2 -0
index a46c69c72..70a214de4 100644
@@ -76,9 +76,11 @@ eal_memalloc_mem_alloc_validator_unregister(const char *name, int socket_id);
 int
 eal_memalloc_mem_alloc_validate(int socket_id, size_t new_len);
 
+/* returns fd or -errno */
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
 
+/* returns 0 or -errno */
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
 
lib/librte_eal/common/include/rte_memory.h +48 -0

54 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memalloc.c +14 -7
index b820989e9..21f842753 100644
@@ -34,6 +34,7 @@
 #include <rte_log.h>
 #include <rte_eal_memconfig.h>
 #include <rte_eal.h>
+#include <rte_errno.h>
 #include <rte_memory.h>
 #include <rte_spinlock.h>
 
@@ -1381,7 +1382,7 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 		int len = mcfg->memsegs[list_idx].memseg_arr.len;
 
 		if (alloc_list(list_idx, len) < 0)
-			return -1;
+			return -ENOMEM;
 	}
 	fd_list[list_idx].fds[seg_idx] = fd;
 
@@ -1391,12 +1392,18 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 int
 eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 {
-	if (internal_config.single_file_segments)
-		return fd_list[list_idx].memseg_list_fd;
-	/* list not initialized */
-	if (fd_list[list_idx].len == 0)
-		return -1;
-	return fd_list[list_idx].fds[seg_idx];
+	int fd;
+	if (internal_config.single_file_segments) {
+		fd = fd_list[list_idx].memseg_list_fd;
+	} else if (fd_list[list_idx].len == 0) {
+		/* list not initialized */
+		fd = -1;
+	} else {
+		fd = fd_list[list_idx].fds[seg_idx];
+	}
+	if (fd < 0)
+		return -ENODEV;
+	return fd;
 }
 
 int
lib/librte_eal/rte_eal_version.map +2 -0
index 344a43d32..e659e19d6 100644
@@ -320,6 +320,8 @@ EXPERIMENTAL {
 	rte_mem_virt2memseg_list;
 	rte_memseg_contig_walk;
 	rte_memseg_contig_walk_thread_unsafe;
+	rte_memseg_get_fd;
+	rte_memseg_get_fd_thread_unsafe;
 	rte_memseg_list_walk;
 	rte_memseg_list_walk_thread_unsafe;
 	rte_memseg_walk;
Signature · 1 line
2.17.1
Reviewed-by on v3 7/9
#37 lore raw

Re: [PATCH v3 7/9] mem: add external API to retrieve page fd from EAL

Quoted 10 lines · Anatoly Burakov

Now that we can retrieve page fd's internally, we can expose it as an external API. This will add two flavors of API - thread-safe and non-thread-safe. Fix up internal API's to return values we need without modifying rte_errno internally if called from within EAL.

We do not want calling code to accidentally close an internal fd, so we make a duplicate of it before we return it to the user. Caller is therefore responsible for closing this fd.

Quoted 9 lines
---
  lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  5 ++-
  lib/librte_eal/common/eal_common_memory.c  | 49 ++++++++++++++++++++++
  lib/librte_eal/common/eal_memalloc.h       |  2 +
  lib/librte_eal/common/include/rte_memory.h | 48 +++++++++++++++++++++
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 21 ++++++----
  lib/librte_eal/rte_eal_version.map         |  2 +
  6 files changed, 118 insertions(+), 9 deletions(-)
#38 lore raw

PATCH v3 8/9 mem: allow querying offset into segment fd

In reply to Anatoly Burakov

In a few cases, user may need to query offset into fd for a particular memory segment (for example, to selectively map pages). This commit adds a new API to do that.

---

Notes:
v3:
- Fix single file segments mode not working

 lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  6 +++
 lib/librte_eal/common/eal_common_memory.c  | 50 ++++++++++++++++++++++
 lib/librte_eal/common/eal_memalloc.h       |  3 ++
 lib/librte_eal/common/include/rte_memory.h | 49 +++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 24 +++++++++++
 lib/librte_eal/rte_eal_version.map         |  2 +
 6 files changed, 134 insertions(+)
lib/librte_eal/bsdapp/eal/eal_memalloc.c +6 -0
index 80e4c3d4f..06afbcc99 100644
@@ -60,6 +60,12 @@ eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd)
 	return -ENOTSUP;
 }
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)
+{
+	return -ENOTSUP;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/common/eal_common_memory.c +50 -0

56 lines not on this page · raw message

lib/librte_eal/common/eal_memalloc.h +3 -0
index 70a214de4..af917c2f9 100644
@@ -84,6 +84,9 @@ eal_memalloc_get_seg_fd(int list_idx, int seg_idx);
 int
 eal_memalloc_set_seg_fd(int list_idx, int seg_idx, int fd);
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset);
+
 int
 eal_memalloc_init(void);
 
lib/librte_eal/common/include/rte_memory.h +49 -0

55 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memalloc.c +24 -0
index 21f842753..6fc9dc0ca 100644
@@ -1406,6 +1406,30 @@ eal_memalloc_get_seg_fd(int list_idx, int seg_idx)
 	return fd;
 }
 
+int
+eal_memalloc_get_seg_fd_offset(int list_idx, int seg_idx, size_t *offset)
+{
+	struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
+
+	/* fd_list not initialized? */
+	if (fd_list[list_idx].len == 0)
+		return -ENODEV;
+	if (internal_config.single_file_segments) {
+		size_t pgsz = mcfg->memsegs[list_idx].page_sz;
+
+		/* segment not active? */
+		if (fd_list[list_idx].memseg_list_fd < 0)
+			return -ENOENT;
+		*offset = pgsz * seg_idx;
+	} else {
+		/* segment not active? */
+		if (fd_list[list_idx].fds[seg_idx] < 0)
+			return -ENOENT;
+		*offset = 0;
+	}
+	return 0;
+}
+
 int
 eal_memalloc_init(void)
 {
lib/librte_eal/rte_eal_version.map +2 -0
index e659e19d6..ba159f7cd 100644
@@ -321,7 +321,9 @@ EXPERIMENTAL {
 	rte_memseg_contig_walk;
 	rte_memseg_contig_walk_thread_unsafe;
 	rte_memseg_get_fd;
+	rte_memseg_get_fd_offset;
 	rte_memseg_get_fd_thread_unsafe;
+	rte_memseg_get_fd_offset_thread_unsafe;
 	rte_memseg_list_walk;
 	rte_memseg_list_walk_thread_unsafe;
 	rte_memseg_walk;
Signature · 1 line
2.17.1
Reviewed-by on v3 8/9
#39 lore raw

Re: [PATCH v3 8/9] mem: allow querying offset into segment fd

Quoted 11 lines · Anatoly Burakov

In a few cases, user may need to query offset into fd for a particular memory segment (for example, to selectively map pages). This commit adds a new API to do that.

---

Notes:
v3:
- Fix single file segments mode not working

Quoted 8 lines
  lib/librte_eal/bsdapp/eal/eal_memalloc.c   |  6 +++
  lib/librte_eal/common/eal_common_memory.c  | 50 ++++++++++++++++++++++
  lib/librte_eal/common/eal_memalloc.h       |  3 ++
  lib/librte_eal/common/include/rte_memory.h | 49 +++++++++++++++++++++
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 24 +++++++++++
  lib/librte_eal/rte_eal_version.map         |  2 +
  6 files changed, 134 insertions(+)

Thanks,
Maxime

#40 lore raw

PATCH v3 9/9 mem: support using memfd segments for in-memory mode

In reply to Anatoly Burakov

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

---
 lib/librte_eal/common/eal_common_options.c |   6 +-
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
 2 files changed, 235 insertions(+), 36 deletions(-)
lib/librte_eal/common/eal_common_options.c +3 -3
index 873099acc..ddd624110 100644
@@ -1384,10 +1384,10 @@ eal_check_common_options(struct internal_config *internal_cfg)
 			" is only supported in non-legacy memory mode\n");
 	}
 	if (internal_cfg->single_file_segments &&
-			internal_cfg->hugepage_unlink) {
+			internal_cfg->hugepage_unlink &&
+			!internal_cfg->in_memory) {
 		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
-			"not compatible with neither --"OPT_IN_MEMORY" nor "
-			"--"OPT_HUGE_UNLINK"\n");
+			"not compatible with --"OPT_HUGE_UNLINK"\n");
 		return -1;
 	}
 	if (internal_cfg->legacy_mem &&
lib/librte_eal/linuxapp/eal/eal_memalloc.c +232 -33

349 lines not on this page · raw message

Signature · 1 line
2.17.1
Reviewed-by on v3 9/9
#41 lore raw

Re: [PATCH v3 9/9] mem: support using memfd segments for in-memory mode

Quoted 14 lines · Anatoly Burakov

Enable using memfd-created segments if supported by the system.

This will allow having real fd's for pages but without hugetlbfs mounts, which will enable in-memory mode to be used with virtio.

The implementation is mostly piggy-backing on existing real-fd code, except that we no longer need to unlink any files or track per-page locks in single-file segments mode, because in-memory mode does not support secondary processes anyway.

We move some checks from EAL command-line parsing code to memalloc because it is now possible to use single-file segments mode with in-memory mode, but only if memfd is supported.

Quoted 5 lines
---
  lib/librte_eal/common/eal_common_options.c |   6 +-
  lib/librte_eal/linuxapp/eal/eal_memalloc.c | 265 ++++++++++++++++++---
  2 files changed, 235 insertions(+), 36 deletions(-)

Thanks,
Maxime

#42 lore raw
In reply to Anatoly Burakov
Quoted 10 lines

Anatoly Burakov (9):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: allow querying offset into segment fd
mem: support using memfd segments for in-memory mode

Applied, tha nks

#43 lore raw
Quoted 11 lines · Thomas Monjalon
Quoted 10 lines

Anatoly Burakov (9):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: allow querying offset into segment fd
mem: support using memfd segments for in-memory mode

Quoted 2 lines

Applied, tha nks

You're welc ome!

Signature · 2 lines
Thanks,
Anatoly
#44 lore raw

19/09/2018 15:55, Burakov, Anatoly:

Quoted 12 lines · Thomas Monjalon
Quoted 11 lines
Quoted 10 lines

Anatoly Burakov (9):
fbarray: fix detach in noshconf mode
eal: don't allow legacy mode with in-memory mode
mem: raise maximum fd limit unconditionally
memalloc: rename lock list to fd list
memalloc: track page fd's in non-single file mode
memalloc: add EAL-internal API to get and set segment fd's
mem: add external API to retrieve page fd from EAL
mem: allow querying offset into segment fd
mem: support using memfd segments for in-memory mode

Quoted 4 lines
Quoted 2 lines

Applied, tha nks

You're welc ome!

On a french keyboard, "tab" is the key next to "a", so I may forgive myself. But looking at "c" and "o" layout, I think your fingers are way bigger than mines :)