Replace open-coded string parsing of /proc/mounts with the standard getmntent(3) routines available on Linux and BSD.
When hugepage_dir is explicitly specified, use statfs() to validate the mount directly rather than scanning /proc/mounts. Using the C library handles edge cases like escaped strings in mount paths automatically. Signed-off-by: Stephen Hemminger <[email protected]> Acked-by: Bruce Richardson <[email protected]> Acked-by: Konstantin Ananyev <[email protected]> --- lib/eal/linux/eal_hugepage_info.c | 104 +++++++++--------------------- 1 file changed, 29 insertions(+), 75 deletions(-) diff --git a/lib/eal/linux/eal_hugepage_info.c b/lib/eal/linux/eal_hugepage_info.c index d47a19c56a..f6d7098a07 100644 --- a/lib/eal/linux/eal_hugepage_info.c +++ b/lib/eal/linux/eal_hugepage_info.c @@ -13,10 +13,13 @@ #include <inttypes.h> #include <unistd.h> #include <errno.h> +#include <mntent.h> #include <sys/mman.h> #include <sys/stat.h> +#include <sys/statfs.h> #include <linux/mman.h> /* for hugetlb-related flags */ +#include <linux/magic.h> /* for HUGETLBFS_MAGIC */ #include <rte_lcore.h> #include <rte_debug.h> @@ -195,109 +198,60 @@ get_default_hp_size(void) static int get_hugepage_dir(uint64_t hugepage_sz, char *hugedir, int len) { - enum proc_mount_fieldnames { - DEVICE = 0, - MOUNTPT, - FSTYPE, - OPTIONS, - _FIELDNAME_MAX - }; static uint64_t default_size = 0; - const char proc_mounts[] = "/proc/mounts"; - const char hugetlbfs_str[] = "hugetlbfs"; - const size_t htlbfs_str_len = sizeof(hugetlbfs_str) - 1; const char pagesize_opt[] = "pagesize="; const size_t pagesize_opt_len = sizeof(pagesize_opt) - 1; - const char split_tok = ' '; - char *splitstr[_FIELDNAME_MAX]; - char found[PATH_MAX] = ""; - char buf[BUFSIZ]; const struct internal_config *internal_conf = eal_get_internal_configuration(); - const size_t hugepage_dir_len = (internal_conf->hugepage_dir != NULL) ? - strlen(internal_conf->hugepage_dir) : 0; - struct stat st; + struct mntent *mnt; + FILE *fp; - /* - * If the specified dir doesn't exist, we can't match it. - */ - if (internal_conf->hugepage_dir != NULL && - stat(internal_conf->hugepage_dir, &st) != 0) { - return -1; + /* Fast path: hugepage_dir explicitly specified */ + if (internal_conf->hugepage_dir != NULL) { + struct statfs sfs; + + /* Query info about mounted filesystem */ + if (statfs(internal_conf->hugepage_dir, &sfs) != 0 || + sfs.f_type != HUGETLBFS_MAGIC || + (uint64_t)sfs.f_bsize != hugepage_sz) + return -1; + + strlcpy(hugedir, internal_conf->hugepage_dir, len); + return 0; } - FILE *fd = fopen(proc_mounts, "r"); - if (fd == NULL) - rte_panic("Cannot open %s\n", proc_mounts); + /* Discover mount point from /proc/mounts */ + fp = setmntent("/proc/mounts", "r"); + if (fp == NULL) + rte_panic("Cannot open /proc/mounts\n"); if (default_size == 0) default_size = get_default_hp_size(); - while (fgets(buf, sizeof(buf), fd)){ + while ((mnt = getmntent(fp)) != NULL) { const char *pagesz_str; - size_t mountpt_len = 0; - - if (rte_strsplit(buf, sizeof(buf), splitstr, _FIELDNAME_MAX, - split_tok) != _FIELDNAME_MAX) { - EAL_LOG(ERR, "Error parsing %s", proc_mounts); - break; /* return NULL */ - } - if (strncmp(splitstr[FSTYPE], hugetlbfs_str, htlbfs_str_len) != 0) + if (strcmp(mnt->mnt_type, "hugetlbfs") != 0) continue; - pagesz_str = strstr(splitstr[OPTIONS], pagesize_opt); + pagesz_str = hasmntopt(mnt, "pagesize"); - /* if no explicit page size, the default page size is compared */ if (pagesz_str == NULL) { if (hugepage_sz != default_size) continue; - } - /* there is an explicit page size, so check it */ - else { + } else { uint64_t pagesz = rte_str_to_size(&pagesz_str[pagesize_opt_len]); if (pagesz != hugepage_sz) continue; } - /* - * If no --huge-dir option has been given, we're done. - */ - if (internal_conf->hugepage_dir == NULL) { - strlcpy(found, splitstr[MOUNTPT], len); - break; - } - - mountpt_len = strlen(splitstr[MOUNTPT]); - - /* - * Ignore any mount that doesn't contain the --huge-dir directory - * or where mount point is not a parent path of --huge-dir - */ - if (strncmp(internal_conf->hugepage_dir, splitstr[MOUNTPT], - mountpt_len) != 0 || - (hugepage_dir_len > mountpt_len && - internal_conf->hugepage_dir[mountpt_len] != '/')) { - continue; - } - - /* - * We found a match, but only prefer it if it's a longer match - * (so /mnt/1 is preferred over /mnt for matching /mnt/1/2)). - */ - if (mountpt_len > strlen(found)) - strlcpy(found, splitstr[MOUNTPT], len); - } /* end while fgets */ - - fclose(fd); - - if (found[0] != '\0') { - /* If needed, return the requested dir, not the mount point. */ - strlcpy(hugedir, internal_conf->hugepage_dir != NULL ? - internal_conf->hugepage_dir : found, len); + /* Found a match */ + strlcpy(hugedir, mnt->mnt_dir, len); + endmntent(fp); return 0; } + endmntent(fp); return -1; } -- 2.51.0

