Skip to contentSkip to conversation

Support running DPDK without hugetlbfs mountpoint

RFC New Anatoly Burakov 1 participant 11 messages May 31, 2018

lore
Share & tools
lore
#0 lore raw

cover Support running DPDK without hugetlbfs mountpoint

This patchset takes old debug options "--huge-unlink" and "--no-shconf" and replaces them both with a new option, "--no-shared-files". This is a special mode which will disable support for secondary processes, but which will cause DPDK to not create any shared files while running - neither hugepages nor any runtime data (everything will be entirely in memory).

Additionally, on supported kernel/glibc versions (Linux 4.14+, glibc 2.27+), "--no-shared-files" mode will also reserve hugepages using memfd instead of relying on hugetlbfs mountpoint. This will make it possible to use DPDK without hugetlbfs mountpoints (e.g. container use cases).

This changes functionality of several command-line switches, so RFC for now. Maybe we could leave the old switches as they are and deprecate them in the next release?

Anatoly Burakov (10):
eal: add --no-shared-files option
eal: make --no-shconf an alias for --no-shared-files
eal: make --huge-unlink an alias for --no-shared-files
fbarray: support no-shared-files mode
mem: add support for no-shared-files mode
ipc: add support for no-shared-files mode
eal: add support for no-shared-files for hugepage info
eal: add support for no-shared-files in hugepage data file
eal: do not create runtime dir in no-shared-files mode
mem: enable memfd-based hugepage allocation

 lib/librte_eal/bsdapp/eal/eal.c               |   7 +-
 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c |   4 +
 lib/librte_eal/common/eal_common_fbarray.c    |  71 +++++----
 lib/librte_eal/common/eal_common_memory.c     |   3 +-
 lib/librte_eal/common/eal_common_options.c    |  25 ++--
 lib/librte_eal/common/eal_common_proc.c       |  25 ++++
 lib/librte_eal/common/eal_internal_cfg.h      |   3 +-
 lib/librte_eal/common/eal_options.h           |   7 +-
 lib/librte_eal/linuxapp/eal/eal.c             |  18 ++-
 .../linuxapp/eal/eal_hugepage_info.c          | 140 ++++++++++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 126 +++++++++++++++-
 lib/librte_eal/linuxapp/eal/eal_memfd.h       |  28 ++++
 lib/librte_eal/linuxapp/eal/eal_memory.c      |  19 ++-
 test/test/test_eal_flags.c                    |  18 +--
 14 files changed, 384 insertions(+), 110 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/eal_memfd.h
Signature · 1 line
2.17.0
#1 lore raw

RFC 1/10 eal: add --no-shared-files option

This command-line option will cause DPDK to not create any shared files at runtime, including any shared configuration or hugetlbfs files. This is useful for debug purposes, as well as for certain use cases like containers.

Currently, this option does nothing.

---
 lib/librte_eal/common/eal_common_options.c | 7 +++++++
 lib/librte_eal/common/eal_internal_cfg.h   | 1 +
 lib/librte_eal/common/eal_options.h        | 2 ++
 3 files changed, 10 insertions(+)
lib/librte_eal/common/eal_common_options.c +7 -0
index ecebb2923..38df094de 100644
@@ -66,6 +66,7 @@ eal_long_options[] = {
 	{OPT_NO_HUGE,           0, NULL, OPT_NO_HUGE_NUM          },
 	{OPT_NO_PCI,            0, NULL, OPT_NO_PCI_NUM           },
 	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHCONF_NUM        },
+	{OPT_NO_SHARED_FILES,   0, NULL, OPT_NO_SHARED_FILES_NUM  },
 	{OPT_PCI_BLACKLIST,     1, NULL, OPT_PCI_BLACKLIST_NUM    },
 	{OPT_PCI_WHITELIST,     1, NULL, OPT_PCI_WHITELIST_NUM    },
 	{OPT_PROC_TYPE,         1, NULL, OPT_PROC_TYPE_NUM        },
@@ -1165,6 +1166,10 @@ eal_parse_common_option(int opt, const char *optarg,
 		conf->no_shconf = 1;
 		break;
 
+	case OPT_NO_SHARED_FILES_NUM:
+		conf->no_shared_files = 1;
+		break;
+
 	case OPT_PROC_TYPE_NUM:
 		conf->process_type = eal_parse_proc_type(optarg);
 		break;
@@ -1370,6 +1375,8 @@ eal_common_usage(void)
 	       "                      Set specific log level\n"
 	       "  -v                  Display version information on startup\n"
 	       "  -h, --help          This help\n"
+	       "  --"OPT_NO_SHARED_FILES"   Do not create any shared files (config, hugetlbfs, etc.).\n"
+	       "                      This disables secondary process support\n"
 	       "\nEAL options for DEBUG use only:\n"
 	       "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
lib/librte_eal/common/eal_internal_cfg.h +1 -0
index c4cbf3acd..3fc71bb49 100644
@@ -41,6 +41,7 @@ struct internal_config {
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
 										* instead of native TSC */
 	volatile unsigned no_shconf;      /**< true if there is no shared config */
+	volatile unsigned no_shared_files; /**< true if there are no shared files to be created*/
 	volatile unsigned create_uio_dev; /**< true to create /dev/uioX devices */
 	volatile enum rte_proc_type_t process_type; /**< multi-process proc type */
 	/** true to try allocating memory on specific sockets */
lib/librte_eal/common/eal_options.h +2 -0
index 211ae06ae..b0d9d6819 100644
@@ -45,6 +45,8 @@ enum {
 	OPT_NO_PCI_NUM,
 #define OPT_NO_SHCONF         "no-shconf"
 	OPT_NO_SHCONF_NUM,
+#define OPT_NO_SHARED_FILES   "no-shared-files"
+	OPT_NO_SHARED_FILES_NUM,
 #define OPT_SOCKET_MEM        "socket-mem"
 	OPT_SOCKET_MEM_NUM,
 #define OPT_SYSLOG            "syslog"
Signature · 1 line
2.17.0
#2 lore raw

RFC 2/10 eal: make --no-shconf an alias for --no-shared-files

In reply to Anatoly Burakov

Move all functionality associated with --no-shconf to --no-shared-files, and make the former an alias for the latter.

---
 lib/librte_eal/bsdapp/eal/eal.c            |  4 ++--
 lib/librte_eal/common/eal_common_memory.c  |  3 ++-
 lib/librte_eal/common/eal_common_options.c |  8 ++------
 lib/librte_eal/common/eal_internal_cfg.h   |  1 -
 lib/librte_eal/common/eal_options.h        |  2 +-
 lib/librte_eal/linuxapp/eal/eal.c          |  6 +++---
 test/test/test_eal_flags.c                 | 18 +++++++++---------
 7 files changed, 19 insertions(+), 23 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +2 -2
index dc279542d..4dff1804e 100644
@@ -222,7 +222,7 @@ rte_eal_config_create(void)
 
 	const char *pathname = eal_runtime_config_path();
 
-	if (internal_config.no_shconf)
+	if (internal_config.no_shared_files)
 		return;
 
 	if (mem_cfg_fd < 0){
@@ -261,7 +261,7 @@ rte_eal_config_attach(void)
 	void *rte_mem_cfg_addr;
 	const char *pathname = eal_runtime_config_path();
 
-	if (internal_config.no_shconf)
+	if (internal_config.no_shared_files)
 		return;
 
 	if (mem_cfg_fd < 0){
lib/librte_eal/common/eal_common_memory.c +2 -1
index 4f0688f9d..a9c4b9b68 100644
@@ -938,7 +938,8 @@ rte_eal_memory_init(void)
 	if (retval < 0)
 		goto fail;
 
-	if (internal_config.no_shconf == 0 && rte_eal_memdevice_init() < 0)
+	if (internal_config.no_shared_files == 0 &&
+			rte_eal_memdevice_init() < 0)
 		goto fail;
 
 	return 0;
lib/librte_eal/common/eal_common_options.c +2 -6
index 38df094de..0f3eb928a 100644
@@ -65,7 +65,7 @@ eal_long_options[] = {
 	{OPT_NO_HPET,           0, NULL, OPT_NO_HPET_NUM          },
 	{OPT_NO_HUGE,           0, NULL, OPT_NO_HUGE_NUM          },
 	{OPT_NO_PCI,            0, NULL, OPT_NO_PCI_NUM           },
-	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHCONF_NUM        },
+	{OPT_NO_SHCONF,         0, NULL, OPT_NO_SHARED_FILES_NUM  },
 	{OPT_NO_SHARED_FILES,   0, NULL, OPT_NO_SHARED_FILES_NUM  },
 	{OPT_PCI_BLACKLIST,     1, NULL, OPT_PCI_BLACKLIST_NUM    },
 	{OPT_PCI_WHITELIST,     1, NULL, OPT_PCI_WHITELIST_NUM    },
@@ -1162,10 +1162,6 @@ eal_parse_common_option(int opt, const char *optarg,
 		conf->vmware_tsc_map = 1;
 		break;
 
-	case OPT_NO_SHCONF_NUM:
-		conf->no_shconf = 1;
-		break;
-
 	case OPT_NO_SHARED_FILES_NUM:
 		conf->no_shared_files = 1;
 		break;
@@ -1382,6 +1378,6 @@ eal_common_usage(void)
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
 	       "  --"OPT_NO_PCI"            Disable PCI\n"
 	       "  --"OPT_NO_HPET"           Disable HPET\n"
-	       "  --"OPT_NO_SHCONF"         No shared config (mmap'd files)\n"
+	       "  --"OPT_NO_SHCONF"         Deprecated. Alias for --no-shared-files\n"
 	       "\n", RTE_MAX_LCORE);
 }
lib/librte_eal/common/eal_internal_cfg.h +0 -1
index 3fc71bb49..d80bacd4d 100644
@@ -40,7 +40,6 @@ struct internal_config {
 	volatile unsigned no_hpet;        /**< true to disable HPET */
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
 										* instead of native TSC */
-	volatile unsigned no_shconf;      /**< true if there is no shared config */
 	volatile unsigned no_shared_files; /**< true if there are no shared files to be created*/
 	volatile unsigned create_uio_dev; /**< true to create /dev/uioX devices */
 	volatile enum rte_proc_type_t process_type; /**< multi-process proc type */
lib/librte_eal/common/eal_options.h +1 -1
index b0d9d6819..6890d4114 100644
@@ -43,8 +43,8 @@ enum {
 	OPT_NO_HUGE_NUM,
 #define OPT_NO_PCI            "no-pci"
 	OPT_NO_PCI_NUM,
+/* no-shconf is an alias for no-shared-files */
 #define OPT_NO_SHCONF         "no-shconf"
-	OPT_NO_SHCONF_NUM,
 #define OPT_NO_SHARED_FILES   "no-shared-files"
 	OPT_NO_SHARED_FILES_NUM,
 #define OPT_SOCKET_MEM        "socket-mem"
lib/librte_eal/linuxapp/eal/eal.c +3 -3
index 8655b8691..32ca25dc2 100644
@@ -230,7 +230,7 @@ rte_eal_config_create(void)
 
 	const char *pathname = eal_runtime_config_path();
 
-	if (internal_config.no_shconf)
+	if (internal_config.no_shared_files)
 		return;
 
 	/* map the config before hugepage address so that we don't waste a page */
@@ -283,7 +283,7 @@ rte_eal_config_attach(void)
 
 	const char *pathname = eal_runtime_config_path();
 
-	if (internal_config.no_shconf)
+	if (internal_config.no_shared_files)
 		return;
 
 	if (mem_cfg_fd < 0){
@@ -309,7 +309,7 @@ rte_eal_config_reattach(void)
 	struct rte_mem_config *mem_config;
 	void *rte_mem_cfg_addr;
 
-	if (internal_config.no_shconf)
+	if (internal_config.no_shared_files)
 		return;
 
 	/* save the address primary process has mapped shared config to */
test/test/test_eal_flags.c +9 -9
index f840ca50b..8e83ea7bf 100644
@@ -27,7 +27,7 @@
 #define mp_flag "--proc-type=secondary"
 #define no_hpet "--no-hpet"
 #define no_huge "--no-huge"
-#define no_shconf "--no-shconf"
+#define no_shared_files "--no-shared-files"
 #define pci_whitelist "--pci-whitelist"
 #define vdev "--vdev"
 #define memtest "memtest"
@@ -370,7 +370,7 @@ test_invalid_vdev_flag(void)
 #ifdef RTE_EXEC_ENV_BSDAPP
 	/* BSD target doesn't support prefixes at this point, and we also need to
 	 * run another primary process here */
-	const char * prefix = no_shconf;
+	const char * prefix = no_shared_files;
 #else
 	const char * prefix = "--file-prefix=vdev";
 #endif
@@ -662,15 +662,15 @@ test_invalid_n_flag(void)
 #endif
 
 	/* -n flag but no value */
-	const char *argv1[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n"};
+	const char *argv1[] = { prgname, prefix, no_huge, no_shared_files, "-c", "1", "-n"};
 	/* bad numeric value */
-	const char *argv2[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "e" };
+	const char *argv2[] = { prgname, prefix, no_huge, no_shared_files, "-c", "1", "-n", "e" };
 	/* zero is invalid */
-	const char *argv3[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "0" };
+	const char *argv3[] = { prgname, prefix, no_huge, no_shared_files, "-c", "1", "-n", "0" };
 	/* sanity test - check with good value */
-	const char *argv4[] = { prgname, prefix, no_huge, no_shconf, "-c", "1", "-n", "2" };
+	const char *argv4[] = { prgname, prefix, no_huge, no_shared_files, "-c", "1", "-n", "2" };
 	/* sanity test - check with no -n flag */
-	const char *argv5[] = { prgname, prefix, no_huge, no_shconf, "-c", "1"};
+	const char *argv5[] = { prgname, prefix, no_huge, no_shared_files, "-c", "1"};
 
 	if (launch_proc(argv1) == 0
 			|| launch_proc(argv2) == 0
@@ -734,7 +734,7 @@ test_no_huge_flag(void)
 #ifdef RTE_EXEC_ENV_BSDAPP
 	/* BSD target doesn't support prefixes at this point, and we also need to
 	 * run another primary process here */
-	const char * prefix = no_shconf;
+	const char * prefix = no_shared_files;
 #else
 	const char * prefix = "--file-prefix=nohuge";
 #endif
@@ -851,7 +851,7 @@ test_misc_flags(void)
 	const char *argv5[] = {prgname, prefix, mp_flag, "-c", "1", "--syslog", "error"};
 	/* With no-sh-conf */
 	const char *argv6[] = {prgname, "-c", "1", "-n", "2", "-m", DEFAULT_MEM_SIZE,
-			no_shconf, nosh_prefix };
+			no_shared_files, nosh_prefix };
 
 #ifdef RTE_EXEC_ENV_BSDAPP
 	return 0;
Signature · 1 line
2.17.0
#3 lore raw

RFC 3/10 eal: make --huge-unlink an alias for --no-shared-files

In reply to Anatoly Burakov

Move all functionality associated with --huge-unlink command-line option to --no-shared-files, and make it an alias. Since the new command-line option does things other than just unlinking hugepage files after they've been created, it is no longer incompatible with --no-huge option, so removing that check as well.

---
 lib/librte_eal/common/eal_common_options.c | 14 ++------------
 lib/librte_eal/common/eal_internal_cfg.h   |  1 -
 lib/librte_eal/common/eal_options.h        |  5 ++---
 lib/librte_eal/linuxapp/eal/eal_memory.c   |  2 +-
 4 files changed, 5 insertions(+), 17 deletions(-)
lib/librte_eal/common/eal_common_options.c +2 -12
index 0f3eb928a..63e562bdb 100644
@@ -57,7 +57,7 @@ eal_long_options[] = {
 	{OPT_FILE_PREFIX,       1, NULL, OPT_FILE_PREFIX_NUM      },
 	{OPT_HELP,              0, NULL, OPT_HELP_NUM             },
 	{OPT_HUGE_DIR,          1, NULL, OPT_HUGE_DIR_NUM         },
-	{OPT_HUGE_UNLINK,       0, NULL, OPT_HUGE_UNLINK_NUM      },
+	{OPT_HUGE_UNLINK,       0, NULL, OPT_NO_SHARED_FILES_NUM  },
 	{OPT_LCORES,            1, NULL, OPT_LCORES_NUM           },
 	{OPT_LOG_LEVEL,         1, NULL, OPT_LOG_LEVEL_NUM        },
 	{OPT_MASTER_LCORE,      1, NULL, OPT_MASTER_LCORE_NUM     },
@@ -1140,10 +1140,6 @@ eal_parse_common_option(int opt, const char *optarg,
 		break;
 
 	/* long options */
-	case OPT_HUGE_UNLINK_NUM:
-		conf->hugepage_unlink = 1;
-		break;
-
 	case OPT_NO_HUGE_NUM:
 		conf->no_hugetlbfs = 1;
 		/* no-huge is legacy mem */
@@ -1318,12 +1314,6 @@ eal_check_common_options(struct internal_config *internal_cfg)
 		return -1;
 	}
 
-	if (internal_cfg->no_hugetlbfs && internal_cfg->hugepage_unlink) {
-		RTE_LOG(ERR, EAL, "Option --"OPT_HUGE_UNLINK" cannot "
-			"be specified together with --"OPT_NO_HUGE"\n");
-		return -1;
-	}
-
 	return 0;
 }
 
@@ -1374,7 +1364,7 @@ eal_common_usage(void)
 	       "  --"OPT_NO_SHARED_FILES"   Do not create any shared files (config, hugetlbfs, etc.).\n"
 	       "                      This disables secondary process support\n"
 	       "\nEAL options for DEBUG use only:\n"
-	       "  --"OPT_HUGE_UNLINK"       Unlink hugepage files after init\n"
+	       "  --"OPT_HUGE_UNLINK"       Deprecated. Alias for --no-shared-files\n"
 	       "  --"OPT_NO_HUGE"           Use malloc instead of hugetlbfs\n"
 	       "  --"OPT_NO_PCI"            Disable PCI\n"
 	       "  --"OPT_NO_HPET"           Disable HPET\n"
lib/librte_eal/common/eal_internal_cfg.h +0 -1
index d80bacd4d..887a6a8e2 100644
@@ -35,7 +35,6 @@ struct internal_config {
 	volatile unsigned force_nchannel; /**< force number of channels */
 	volatile unsigned force_nrank;    /**< force number of ranks */
 	volatile unsigned no_hugetlbfs;   /**< true to disable hugetlbfs */
-	unsigned hugepage_unlink;         /**< true to unlink backing files */
 	volatile unsigned no_pci;         /**< true to disable PCI */
 	volatile unsigned no_hpet;        /**< true to disable HPET */
 	volatile unsigned vmware_tsc_map; /**< true to use VMware TSC mapping
lib/librte_eal/common/eal_options.h +2 -3
index 6890d4114..aef696c92 100644
@@ -25,8 +25,6 @@ enum {
 	OPT_FILE_PREFIX_NUM,
 #define OPT_HUGE_DIR          "huge-dir"
 	OPT_HUGE_DIR_NUM,
-#define OPT_HUGE_UNLINK       "huge-unlink"
-	OPT_HUGE_UNLINK_NUM,
 #define OPT_LCORES            "lcores"
 	OPT_LCORES_NUM,
 #define OPT_LOG_LEVEL         "log-level"
@@ -43,7 +41,8 @@ enum {
 	OPT_NO_HUGE_NUM,
 #define OPT_NO_PCI            "no-pci"
 	OPT_NO_PCI_NUM,
-/* no-shconf is an alias for no-shared-files */
+/* huge-unlink and no-shconf are alias for no-shared-files */
+#define OPT_HUGE_UNLINK       "huge-unlink"
 #define OPT_NO_SHCONF         "no-shconf"
 #define OPT_NO_SHARED_FILES   "no-shared-files"
 	OPT_NO_SHARED_FILES_NUM,
lib/librte_eal/linuxapp/eal/eal_memory.c +1 -1
index c917de1c2..5e1810712 100644
@@ -1547,7 +1547,7 @@ eal_legacy_hugepage_init(void)
 	}
 
 	/* free the hugepage backing files */
-	if (internal_config.hugepage_unlink &&
+	if (internal_config.no_shared_files &&
 		unlink_hugepage_files(tmp_hp, internal_config.num_hugepage_sizes) < 0) {
 		RTE_LOG(ERR, EAL, "Unlinking hugepage files failed!\n");
 		goto fail;
Signature · 1 line
2.17.0
#4 lore raw

RFC 4/10 fbarray: support no-shared-files mode

In reply to Anatoly Burakov

When using --no-shared-files option, the expectation is that no multiprocess will be supported as no shared files are created. However, fbarray still creates some shared files that prevent multiple processes with the same prefix from starting.

Fix this by avoiding creating shared files whenever noshconf option is specified. Since virtual areas we get from eal_get_virtual_area() are read-only, remap them as writable.

---
 lib/librte_eal/common/eal_common_fbarray.c | 71 +++++++++++++---------
 1 file changed, 42 insertions(+), 29 deletions(-)
lib/librte_eal/common/eal_common_fbarray.c +42 -29
index 019f84c18..69576c8a8 100644
@@ -434,39 +434,52 @@ rte_fbarray_init(struct rte_fbarray *arr, const char *name, unsigned int len,
 	if (data == NULL)
 		goto fail;
 
-	eal_get_fbarray_path(path, sizeof(path), name);
+	if (internal_config.no_shared_files) {
+		/* remap virtual area as writable */
+		void *new_data = mmap(data, mmap_len, PROT_READ | PROT_WRITE,
+				MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (new_data == MAP_FAILED) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't remap anonymous memory: %s\n",
+					__func__, strerror(errno));
+			goto fail;
+		}
+	} else {
+		eal_get_fbarray_path(path, sizeof(path), name);
 
-	/*
-	 * Each fbarray is unique to process namespace, i.e. the filename
-	 * depends on process prefix. Try to take out a lock and see if we
-	 * succeed. If we don't, someone else is using it already.
-	 */
-	fd = open(path, O_CREAT | O_RDWR, 0600);
-	if (fd < 0) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = errno;
-		goto fail;
-	} else if (flock(fd, LOCK_EX | LOCK_NB)) {
-		RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n", __func__,
-				path, strerror(errno));
-		rte_errno = EBUSY;
-		goto fail;
-	}
+		/*
+		 * Each fbarray is unique to process namespace, i.e. the
+		 * filename depends on process prefix. Try to take out a lock
+		 * and see if we succeed. If we don't, someone else is using it
+		 * already.
+		 */
+		fd = open(path, O_CREAT | O_RDWR, 0600);
+		if (fd < 0) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't open %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = errno;
+			goto fail;
+		} else if (flock(fd, LOCK_EX | LOCK_NB)) {
+			RTE_LOG(DEBUG, EAL, "%s(): couldn't lock %s: %s\n",
+					__func__, path, strerror(errno));
+			rte_errno = EBUSY;
+			goto fail;
+		}
 
-	/* take out a non-exclusive lock, so that other processes could still
-	 * attach to it, but no other process could reinitialize it.
-	 */
-	if (flock(fd, LOCK_SH | LOCK_NB)) {
-		rte_errno = errno;
-		goto fail;
-	}
+		/* take out a non-exclusive lock, so that other processes could
+		 * still attach to it, but no other process could reinitialize
+		 * it.
+		 */
+		if (flock(fd, LOCK_SH | LOCK_NB)) {
+			rte_errno = errno;
+			goto fail;
+		}
 
-	if (resize_and_map(fd, data, mmap_len))
-		goto fail;
+		if (resize_and_map(fd, data, mmap_len))
+			goto fail;
 
-	/* we've mmap'ed the file, we can now close the fd */
-	close(fd);
+		/* we've mmap'ed the file, we can now close the fd */
+		close(fd);
+	}
 
 	/* initialize the data */
 	memset(data, 0, mmap_len);
Signature · 1 line
2.17.0
#5 lore raw

RFC 5/10 mem: add support for no-shared-files mode

In reply to Anatoly Burakov

Unlink hugepages after creating them, to honor the no shared files mode. We cannot resize non-existing files, so make single file segments explicitly unsupported.

---
 lib/librte_eal/linuxapp/eal/eal.c          |  9 +++++++++
 lib/librte_eal/linuxapp/eal/eal_memalloc.c | 23 +++++++++++++++++++---
 2 files changed, 29 insertions(+), 3 deletions(-)
lib/librte_eal/linuxapp/eal/eal.c +9 -0
index 32ca25dc2..7904f813e 100644
@@ -690,6 +690,15 @@ eal_parse_args(int argc, char **argv)
 		goto out;
 	}
 
+	if (internal_config.single_file_segments &&
+			internal_config.no_shared_files) {
+		RTE_LOG(ERR, EAL, "Option --"OPT_SINGLE_FILE_SEGMENTS" is "
+			"incompatible with --"OPT_NO_SHARED_FILES"\n");
+		eal_usage(prgname);
+		ret = -1;
+		goto out;
+	}
+
 	if (optind >= 0)
 		argv[optind-1] = prgname;
 	ret = optind-1;
lib/librte_eal/linuxapp/eal/eal_memalloc.c +20 -3
index 8c11f98c9..f57d307dd 100644
@@ -512,6 +512,13 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 				__func__, strerror(errno));
 			goto resized;
 		}
+		if (internal_config.no_shared_files) {
+			if (unlink(path)) {
+				RTE_LOG(DEBUG, EAL, "%s(): unlink() failed: %s\n",
+					__func__, strerror(errno));
+				goto resized;
+			}
+		}
 	}
 
 	/*
@@ -562,8 +569,11 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 			(unsigned int)(alloc_sz >> 20));
 		goto mapped;
 	}
-	/* for non-single file segments, we can close fd here */
-	if (!internal_config.single_file_segments)
+	/* for non-single file segments or no shared files mode, we can close fd
+	 * here
+	 */
+	if (!internal_config.single_file_segments ||
+			internal_config.no_shared_files)
 		close(fd);
 
 	/* we need to trigger a write to the page to enforce page fault and
@@ -592,7 +602,8 @@ alloc_seg(struct rte_memseg *ms, void *addr, int socket_id,
 		/* ignore failure, can't make it any worse */
 	} else {
 		/* only remove file if we can take out a write lock */
-		if (lock(fd, LOCK_EX) == 1)
+		if (internal_config.no_shared_files == 0 &&
+				lock(fd, LOCK_EX) == 1)
 			unlink(path);
 		close(fd);
 	}
@@ -617,6 +628,12 @@ free_seg(struct rte_memseg *ms, struct hugepage_info *hi,
 		return -1;
 	}
 
+	/* if we're no in shared files mode, nothing needs to be done */
+	if (internal_config.no_shared_files) {
+		memset(ms, 0, sizeof(*ms));
+		return 0;
+	}
+
 	/* if we are not in single file segments mode, we're going to unmap the
 	 * segment and thus drop the lock on original fd, but hugepage dir is
 	 * now locked so we can take out another one without races.
Signature · 1 line
2.17.0
#6 lore raw

RFC 6/10 ipc: add support for no-shared-files mode

In reply to Anatoly Burakov

IPC is an inter-process communication mechanism. Since no secondaries can ever be expected to run in no shared files mode, IPC will be useless, so do not enable it in the first place. In the interests of API usage convenience, we will still allow registering callbacks, but obviously they won't ever be triggered.

---
 lib/librte_eal/common/eal_common_proc.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)
lib/librte_eal/common/eal_common_proc.c +25 -0
index 707d8ab30..6cce4e925 100644
@@ -626,6 +626,14 @@ rte_mp_channel_init(void)
 	int dir_fd;
 	pthread_t mp_handle_tid, async_reply_handle_tid;
 
+	/* in no shared files mode, we do not have secondary processes support,
+	 * so no need to initialize IPC.
+	 */
+	if (internal_config.no_shared_files) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC will be disabled\n");
+		return 0;
+	}
+
 	/* create filter path */
 	create_socket_path("*", path, sizeof(path));
 	strlcpy(mp_filter, basename(path), sizeof(mp_filter));
@@ -988,6 +996,12 @@ rte_mp_request_sync(struct rte_mp_msg *req, struct rte_mp_reply *reply,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shared_files) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1072,6 +1086,12 @@ rte_mp_request_async(struct rte_mp_msg *req, const struct timespec *ts,
 
 	if (check_input(req) == false)
 		return -1;
+
+	if (internal_config.no_shared_files) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	if (gettimeofday(&now, NULL) < 0) {
 		RTE_LOG(ERR, EAL, "Faile to get current time\n");
 		rte_errno = errno;
@@ -1213,5 +1233,10 @@ rte_mp_reply(struct rte_mp_msg *msg, const char *peer)
 		return -1;
 	}
 
+	if (internal_config.no_shared_files) {
+		RTE_LOG(DEBUG, EAL, "No shared files mode enabled, IPC is disabled\n");
+		return 0;
+	}
+
 	return mp_send(msg, peer, MP_REP);
 }
Signature · 1 line
2.17.0
#7 lore raw

RFC 7/10 eal: add support for no-shared-files for hugepage info

In reply to Anatoly Burakov

Do not create any shared hugepage size info files if we were asked to not create any shared files.

---
 lib/librte_eal/bsdapp/eal/eal_hugepage_info.c   | 4 ++++
 lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 4 ++++
 2 files changed, 8 insertions(+)
lib/librte_eal/bsdapp/eal/eal_hugepage_info.c +4 -0
index 836feb672..4b2f71c7e 100644
@@ -101,6 +101,10 @@ eal_hugepage_info_init(void)
 	hpi->num_pages[0] = num_buffers;
 	hpi->lock_descriptor = fd;
 
+	/* for no shared files mode, do not create shared memory config */
+	if (internal_config.no_shared_files)
+		return 0;
+
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
 			sizeof(internal_config.hugepage_info));
 	if (tmp_hpi == NULL ) {
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +4 -0
index 7eca711ba..02b1c4ff1 100644
@@ -446,6 +446,10 @@ eal_hugepage_info_init(void)
 	if (hugepage_info_init() < 0)
 		return -1;
 
+	/* for no shared files mode, we're done */
+	if (internal_config.no_shared_files)
+		return 0;
+
 	hpi = &internal_config.hugepage_info[0];
 
 	tmp_hpi = create_shared_memory(eal_hugepage_info_path(),
Signature · 1 line
2.17.0
#8 lore raw

RFC 8/10 eal: add support for no-shared-files in hugepage data file

In reply to Anatoly Burakov

Do not create a shared hugepage data file if we were asked to not create any shared files.

---
 lib/librte_eal/linuxapp/eal/eal_memory.c | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
lib/librte_eal/linuxapp/eal/eal_memory.c +12 -1
index 5e1810712..d7b43b5c1 100644
@@ -521,7 +521,18 @@ static void *
 create_shared_memory(const char *filename, const size_t mem_size)
 {
 	void *retval;
-	int fd = open(filename, O_CREAT | O_RDWR, 0666);
+	int fd;
+
+	/* if no shared files mode is used, create anonymous memory instead */
+	if (internal_config.no_shared_files) {
+		retval = mmap(NULL, mem_size, PROT_READ | PROT_WRITE,
+				MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+		if (retval == MAP_FAILED)
+			return NULL;
+		return retval;
+	}
+
+	fd = open(filename, O_CREAT | O_RDWR, 0666);
 	if (fd < 0)
 		return NULL;
 	if (ftruncate(fd, mem_size) < 0) {
Signature · 1 line
2.17.0
#9 lore raw

RFC 9/10 eal: do not create runtime dir in no-shared-files mode

In reply to Anatoly Burakov

Now that the rest of the EAL is adjusted to not create any shared files, prevent runtime directory from ever being created.

---
 lib/librte_eal/bsdapp/eal/eal.c   | 3 ++-
 lib/librte_eal/linuxapp/eal/eal.c | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
lib/librte_eal/bsdapp/eal/eal.c +2 -1
index 4dff1804e..3ba2502cc 100644
@@ -601,7 +601,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shared_files == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
lib/librte_eal/linuxapp/eal/eal.c +2 -1
index 7904f813e..c0b2b1a5a 100644
@@ -827,7 +827,8 @@ rte_eal_init(int argc, char **argv)
 	}
 
 	/* create runtime data directory */
-	if (eal_create_runtime_dir() < 0) {
+	if (internal_config.no_shared_files == 0 &&
+			eal_create_runtime_dir() < 0) {
 		rte_eal_init_alert("Cannot create runtime directory\n");
 		rte_errno = EACCES;
 		return -1;
Signature · 1 line
2.17.0
#10 lore raw

RFC 10/10 mem: enable memfd-based hugepage allocation

In reply to Anatoly Burakov

This will supplant no-shared-files mode to use memfd-based hugetlbfs allocation instead of hugetlbfs mounts. Due to memfd only being supported kernel 4.14+ and glibc 2.27+, a compile-time check is performed along with runtime checks.

---
 .../linuxapp/eal/eal_hugepage_info.c          | 136 ++++++++++++++----
 lib/librte_eal/linuxapp/eal/eal_memalloc.c    | 105 +++++++++++++-
 lib/librte_eal/linuxapp/eal/eal_memfd.h       |  28 ++++
 lib/librte_eal/linuxapp/eal/eal_memory.c      |   4 +-
 4 files changed, 234 insertions(+), 39 deletions(-)
 create mode 100644 lib/librte_eal/linuxapp/eal/eal_memfd.h
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +105 -31
index 02b1c4ff1..1a80ee0ee 100644
@@ -30,6 +30,7 @@
 #include "eal_internal_cfg.h"
 #include "eal_hugepages.h"
 #include "eal_filesystem.h"
+#include "eal_memfd.h"
 
 static const char sys_dir_path[] = "/sys/kernel/mm/hugepages";
 static const char sys_pages_numa_dir_path[] = "/sys/devices/system/node";
@@ -313,11 +314,85 @@ compare_hpi(const void *a, const void *b)
 	return hpi_b->hugepage_sz - hpi_a->hugepage_sz;
 }
 
+static void
+calc_num_pages(struct hugepage_info *hpi, struct dirent *dirent)
+{
+	uint64_t total_pages = 0;
+	unsigned int i;
+
+	/*
+	 * first, try to put all hugepages into relevant sockets, but
+	 * if first attempts fails, fall back to collecting all pages
+	 * in one socket and sorting them later
+	 */
+	total_pages = 0;
+	/* we also don't want to do this for legacy init */
+	if (!internal_config.legacy_mem)
+		for (i = 0; i < rte_socket_count(); i++) {
+			int socket = rte_socket_id_by_idx(i);
+			unsigned int num_pages =
+					get_num_hugepages_on_node(
+						dirent->d_name, socket);
+			hpi->num_pages[socket] = num_pages;
+			total_pages += num_pages;
+		}
+	/*
+	 * we failed to sort memory from the get go, so fall
+	 * back to old way
+	 */
+	if (total_pages == 0) {
+		hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
+
+#ifndef RTE_ARCH_64
+		/* for 32-bit systems, limit number of hugepages to
+		 * 1GB per page size */
+		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
+				RTE_PGSIZE_1G / hpi->hugepage_sz);
+#endif
+	}
+}
+
+static int
+check_memfd_pagesize_supported(uint64_t page_sz)
+{
+#ifdef MEMFD_SUPPORTED
+	int sz_flag, fd;
+
+	/* first, check if this particular pagesize is supported */
+	sz_flag = eal_memalloc_get_memfd_pagesize_flag(page_sz);
+	if (sz_flag == 0) {
+		RTE_LOG(ERR, EAL, "Unexpected memfd hugepage size: %"
+			PRIu64" bytes\n", page_sz);
+		return 0;
+	}
+
+	/* does currently running kernel support it? */
+	fd = memfd_create("memfd_test", sz_flag | MFD_HUGETLB);
+	if (fd >= 0) {
+		/* success */
+		close(fd);
+		return 1;
+	}
+	/* creating memfd failed, but if the error wasn't EINVAL, reserving of
+	 * hugepages via memfd is supported by the kernel
+	 */
+	if (errno != EINVAL) {
+		return 1;
+	}
+	RTE_LOG(DEBUG, EAL, "Kernel does not support memfd hugepages of size %"
+		PRIu64" bytes\n", page_sz);
+#else
+	RTE_LOG(DEBUG, EAL, "Memfd hugepage support not enabled at compile time\n");
+	RTE_SET_USED(page_sz);
+#endif
+	return 0;
+}
+
 static int
 hugepage_info_init(void)
 {	const char dirent_start_text[] = "hugepages-";
 	const size_t dirent_start_len = sizeof(dirent_start_text) - 1;
-	unsigned int i, total_pages, num_sizes = 0;
+	unsigned int i, num_sizes = 0;
 	DIR *dir;
 	struct dirent *dirent;
 
@@ -343,6 +418,10 @@ hugepage_info_init(void)
 		hpi->hugepage_sz =
 			rte_str_to_size(&dirent->d_name[dirent_start_len]);
 
+		/* by default, memfd_hugepage_supported is 1 */
+		memfd_hugepage_supported &=
+			check_memfd_pagesize_supported(hpi->hugepage_sz);
+
 		/* first, check if we have a mountpoint */
 		if (get_hugepage_dir(hpi->hugepage_sz,
 			hpi->hugedir, sizeof(hpi->hugedir)) < 0) {
@@ -355,6 +434,23 @@ hugepage_info_init(void)
 					"%" PRIu64 " reserved, but no mounted "
 					"hugetlbfs found for that size\n",
 					num_pages, hpi->hugepage_sz);
+
+			/* no shared files mode may still be able to allocate
+			 * without a valid mountpoint via memfd, but we cannot
+			 * use memfd in legacy mode, because we cannot sort
+			 * pages, so only allow empty mountpoints in non-legacy
+			 * mode.
+			 */
+			if (internal_config.no_shared_files &&
+					!internal_config.legacy_mem &&
+					memfd_hugepage_supported) {
+				RTE_LOG(NOTICE, EAL, "No shared files mode enabled, "
+					"hugepages of size %" PRIu64 " bytes "
+					"will be allocated anonymously\n",
+					hpi->hugepage_sz);
+				calc_num_pages(hpi, dirent);
+				num_sizes++;
+			}
 			continue;
 		}
 
@@ -371,35 +467,14 @@ hugepage_info_init(void)
 		if (clear_hugedir(hpi->hugedir) == -1)
 			break;
 
-		/*
-		 * first, try to put all hugepages into relevant sockets, but
-		 * if first attempts fails, fall back to collecting all pages
-		 * in one socket and sorting them later
-		 */
-		total_pages = 0;
-		/* we also don't want to do this for legacy init */
-		if (!internal_config.legacy_mem)
-			for (i = 0; i < rte_socket_count(); i++) {
-				int socket = rte_socket_id_by_idx(i);
-				unsigned int num_pages =
-						get_num_hugepages_on_node(
-							dirent->d_name, socket);
-				hpi->num_pages[socket] = num_pages;
-				total_pages += num_pages;
-			}
-		/*
-		 * we failed to sort memory from the get go, so fall
-		 * back to old way
-		 */
-		if (total_pages == 0)
-			hpi->num_pages[0] = get_num_hugepages(dirent->d_name);
+		calc_num_pages(hpi, dirent);
 
-#ifndef RTE_ARCH_64
-		/* for 32-bit systems, limit number of hugepages to
-		 * 1GB per page size */
-		hpi->num_pages[0] = RTE_MIN(hpi->num_pages[0],
-					    RTE_PGSIZE_1G / hpi->hugepage_sz);
-#endif
+		if (internal_config.no_shared_files &&
+				!internal_config.legacy_mem &&
+				memfd_hugepage_supported)
+			RTE_LOG(NOTICE, EAL, "No shared files mode enabled, "
+				"hugepages of size %" PRIu64 " bytes will be "
+				"allocated anonymously\n", hpi->hugepage_sz);
 
 		num_sizes++;
 	}
@@ -423,8 +498,7 @@ hugepage_info_init(void)
 
 		for (j = 0; j < RTE_MAX_NUMA_NODES; j++)
 			num_pages += hpi->num_pages[j];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0 &&
-				num_pages > 0)
+		if (num_pages > 0)
 			return 0;
 	}
 
lib/librte_eal/linuxapp/eal/eal_memalloc.c +99 -6

183 lines not on this page · raw message

lib/librte_eal/linuxapp/eal/eal_memfd.h new file +28 -0
new file mode 100644
index 000000000..55e6dbb2c
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Intel Corporation
+ */
+
+#ifndef EAL_MEMFD_H
+#define EAL_MEMFD_H
+
+#include <stdint.h>
+
+/*
+ * For memfd hugepages, both kernel and glibc version must support them. So,
+ * check for both.
+ */
+#include <features.h> /* glibc version */
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 27
+#include <linux/version.h> /* linux kernel version */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 0)
+#define MEMFD_SUPPORTED
+#include <linux/memfd.h>
+#endif /* linux version check */
+#endif /* glibc version check */
+
+int
+eal_memalloc_get_memfd_pagesize_flag(uint64_t page_sz);
+
+extern int memfd_hugepage_supported;
+
+#endif /* EAL_MEMFD_H */
lib/librte_eal/linuxapp/eal/eal_memory.c +2 -2
index d7b43b5c1..b26e21be8 100644
@@ -44,6 +44,7 @@
 #include "eal_internal_cfg.h"
 #include "eal_filesystem.h"
 #include "eal_hugepages.h"
+#include "eal_memfd.h"
 
 #define PFN_MASK_SIZE	8
 
@@ -1060,8 +1061,7 @@ get_socket_mem_size(int socket)
 
 	for (i = 0; i < internal_config.num_hugepage_sizes; i++){
 		struct hugepage_info *hpi = &internal_config.hugepage_info[i];
-		if (strnlen(hpi->hugedir, sizeof(hpi->hugedir)) != 0)
-			size += hpi->hugepage_sz * hpi->num_pages[socket];
+		size += hpi->hugepage_sz * hpi->num_pages[socket];
 	}
 
 	return size;
Signature · 1 line
2.17.0