From 32832fc6c08ed3f9afbe08ba203d4196f4643a1b Mon Sep 17 00:00:00 2001 From: Intel Date: Thu, 20 Dec 2012 00:00:00 +0100 Subject: [PATCH] lib: sysfs parsing Signed-off-by: Intel --- app/test/Makefile | 1 + app/test/commands.c | 4 +- app/test/test.h | 2 + app/test/test_eal_fs.c | 210 ++++++++++++++++++ lib/librte_eal/linuxapp/eal/eal.c | 34 ++- .../linuxapp/eal/eal_hugepage_info.c | 8 +- lib/librte_eal/linuxapp/eal/eal_memory.c | 2 +- lib/librte_eal/linuxapp/eal/eal_pci.c | 45 +--- .../{eal_fs_paths.h => eal_filesystem.h} | 18 +- 9 files changed, 275 insertions(+), 49 deletions(-) create mode 100644 app/test/test_eal_fs.c rename lib/librte_eal/linuxapp/eal/include/{eal_fs_paths.h => eal_filesystem.h} (85%) diff --git a/app/test/Makefile b/app/test/Makefile index 40e490eb20..d296dbb542 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -71,6 +71,7 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_eal_flags.c SRCS-$(CONFIG_RTE_APP_TEST) += test_alarm.c SRCS-$(CONFIG_RTE_APP_TEST) += test_interrupts.c SRCS-$(CONFIG_RTE_APP_TEST) += test_version.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_eal_fs.c CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) diff --git a/app/test/commands.c b/app/test/commands.c index dc268ed654..71dbf96954 100644 --- a/app/test/commands.c +++ b/app/test/commands.c @@ -93,6 +93,8 @@ static void cmd_autotest_parsed(void *parsed_result, if (all || !strcmp(res->autotest, "version_autotest")) ret |= test_version(); + if (all || !strcmp(res->autotest, "eal_fs_autotest")) + ret |= test_eal_fs(); if (all || !strcmp(res->autotest, "debug_autotest")) ret |= test_debug(); if (all || !strcmp(res->autotest, "pci_autotest")) @@ -177,7 +179,7 @@ cmdline_parse_token_string_t cmd_autotest_autotest = "string_autotest#multiprocess_autotest#" "cpuflags_autotest#eal_flags_autotest#" "alarm_autotest#interrupt_autotest#" - "version_autotest#" + "version_autotest#eal_fs_autotest#" "all_autotests"); cmdline_parse_inst_t cmd_autotest = { diff --git a/app/test/test.h b/app/test/test.h index af683e4d38..d20899204f 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -79,6 +79,8 @@ int test_eal_flags(void); int test_alarm(void); int test_interrupt(void); int test_version(void); +int test_eal_fs(void); + int test_pci_run; #endif diff --git a/app/test/test_eal_fs.c b/app/test/test_eal_fs.c new file mode 100644 index 0000000000..64a70e1095 --- /dev/null +++ b/app/test/test_eal_fs.c @@ -0,0 +1,210 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2012 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include + +#include "test.h" +#ifndef RTE_EXEC_ENV_BAREMETAL +#include +#include +#include + +/* eal_filesystem.h is not a public header file, so use relative path */ +#include "../../lib/librte_eal/linuxapp/eal/include/eal_filesystem.h" + +static int +test_parse_sysfs_value(void) +{ + char filename[PATH_MAX] = ""; + char proc_path[PATH_MAX]; + char file_template[] = "/tmp/eal_test_XXXXXX"; + int tmp_file_handle = -1; + FILE *fd = NULL; + unsigned valid_number; + unsigned long retval = 0; + + printf("Testing function eal_parse_sysfs_value()\n"); + + /* get a temporary filename to use for all tests - create temp file handle and then + * use /proc to get the actual file that we can open */ + tmp_file_handle = mkstemp(file_template); + if (tmp_file_handle == -1) { + perror("mkstemp() failure"); + goto error; + } + rte_snprintf(proc_path, sizeof(proc_path), "/proc/self/fd/%d", tmp_file_handle); + if (readlink(proc_path, filename, sizeof(filename)) < 0) { + perror("readlink() failure"); + goto error; + } + printf("Temporary file is: %s\n", filename); + + /* test we get an error value if we use file before it's created */ + printf("Test reading a missing file ...\n"); + if (eal_parse_sysfs_value("/dev/not-quite-null", &retval) == 0) { + printf("Error with eal_parse_sysfs_value() - returned success on reading empty file\n"); + goto error; + } + printf("Confirmed return error when reading empty file\n"); + + /* test reading a valid number value with "\n" on the end */ + printf("Test reading valid values ...\n"); + valid_number = 15; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%u\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) < 0) { + printf("eal_parse_sysfs_value() returned error - test failed\n"); + goto error; + } + if (retval != valid_number) { + printf("Invalid value read by eal_parse_sysfs_value() - test failed\n"); + goto error; + } + printf("Read '%u\\n' ok\n", valid_number); + + /* test reading a valid hex number value with "\n" on the end */ + valid_number = 25; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"0x%x\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) < 0) { + printf("eal_parse_sysfs_value() returned error - test failed\n"); + goto error; + } + if (retval != valid_number) { + printf("Invalid value read by eal_parse_sysfs_value() - test failed\n"); + goto error; + } + printf("Read '0x%x\\n' ok\n", valid_number); + + printf("Test reading invalid values ...\n"); + + /* test reading an empty file - expect failure!*/ + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a valid number value *without* "\n" on the end - expect failure!*/ + valid_number = 3; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%u", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a valid number value followed by string - expect failure!*/ + valid_number = 3; + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"%uJ\n", valid_number); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + /* test reading a non-numeric value - expect failure!*/ + fd = fopen(filename,"w"); + if (fd == NULL) { + printf("line %d, Error opening %s: %s\n", __LINE__, filename, strerror(errno)); + goto error; + } + fprintf(fd,"error\n"); + fclose(fd); + fd = NULL; + if (eal_parse_sysfs_value(filename, &retval) == 0) { + printf("eal_parse_sysfs_value() read invalid value - test failed\n"); + goto error; + } + + close(tmp_file_handle); + unlink(filename); + printf("eal_parse_sysfs_value() - OK\n"); + return 0; + +error: + if (fd) + fclose(fd); + if (tmp_file_handle > 0) + close(tmp_file_handle); + if (filename[0] != '\0') + unlink(filename); + return -1; +} + +int +test_eal_fs(void) +{ + if (test_parse_sysfs_value() < 0) + return -1; + return 0; +} +#else +/* baremetal does not have a filesystem */ +int +test_eal_fs(void) +{ + return 0; +} +#endif diff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c index 87c62d3fc6..22db385bf4 100644 --- a/lib/librte_eal/linuxapp/eal/eal.c +++ b/lib/librte_eal/linuxapp/eal/eal.c @@ -70,7 +70,7 @@ #include "eal_private.h" #include "eal_thread.h" #include "eal_internal_cfg.h" -#include "eal_fs_paths.h" +#include "eal_filesystem.h" #include "eal_hugepages.h" #define OPT_HUGE_DIR "huge-dir" @@ -131,6 +131,38 @@ rte_eal_get_configuration(void) return &rte_config; } +/* parse a sysfs (or other) file containing one integer value */ +int +eal_parse_sysfs_value(const char *filename, unsigned long *val) +{ + FILE *f; + char buf[BUFSIZ]; + char *end = NULL; + + if ((f = fopen(filename, "r")) == NULL) { + RTE_LOG(ERR, EAL, "%s(): cannot open sysfs value %s\n", + __func__, filename); + return -1; + } + + if (fgets(buf, sizeof(buf), f) == NULL) { + RTE_LOG(ERR, EAL, "%s(): cannot read sysfs value %s\n", + __func__, filename); + fclose(f); + return -1; + } + *val = strtoul(buf, &end, 0); + if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { + RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs value %s\n", + __func__, filename); + fclose(f); + return -1; + } + fclose(f); + return 0; +} + + /* create memory configuration in shared/mmap memory. Take out * a write lock on the memsegs, so we can auto-detect primary/secondary. * This means we never close the file while running (auto-close on exit). diff --git a/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c b/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c index fab678890e..5632ecee9c 100644 --- a/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +++ b/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c @@ -56,6 +56,7 @@ #include "rte_string_fns.h" #include "eal_internal_cfg.h" #include "eal_hugepages.h" +#include "eal_filesystem.h" static const char sys_dir_path[] = "/sys/kernel/mm/hugepages"; @@ -68,10 +69,9 @@ get_num_hugepages(const char *subdir) rte_snprintf(path, sizeof(path), "%s/%s/%s", sys_dir_path, subdir, nr_hp_file); - FILE *fd = fopen(path, "r"); - if (fd == NULL || fscanf(fd, "%u", &num_pages) != 1) - rte_panic("Error reading file '%s'\n", path); - fclose(fd); + + if (eal_parse_sysfs_value(path, &num_pages) < 0) + return 0; return num_pages; } diff --git a/lib/librte_eal/linuxapp/eal/eal_memory.c b/lib/librte_eal/linuxapp/eal/eal_memory.c index dd2afeed91..d76ebd90b4 100644 --- a/lib/librte_eal/linuxapp/eal/eal_memory.c +++ b/lib/librte_eal/linuxapp/eal/eal_memory.c @@ -63,7 +63,7 @@ #include "eal_private.h" #include "eal_internal_cfg.h" -#include "eal_fs_paths.h" +#include "eal_filesystem.h" #include "eal_hugepages.h" /** diff --git a/lib/librte_eal/linuxapp/eal/eal_pci.c b/lib/librte_eal/linuxapp/eal/eal_pci.c index d8a7bcdd95..1903c14f21 100644 --- a/lib/librte_eal/linuxapp/eal/eal_pci.c +++ b/lib/librte_eal/linuxapp/eal/eal_pci.c @@ -66,6 +66,7 @@ #include #include "eal_internal_cfg.h" +#include "eal_filesystem.h" #include "eal_private.h" /** @@ -108,7 +109,6 @@ struct uio_resource { TAILQ_HEAD(uio_res_list, uio_resource); static struct uio_res_list *uio_res_list = NULL; -static int pci_parse_sysfs_value(const char *filename, unsigned long *val); /* * Check that a kernel module is loaded. Returns 0 on success, or if the @@ -366,7 +366,7 @@ pci_uio_map_resource(struct rte_pci_device *dev) /* get mapping offset */ rte_snprintf(filename, sizeof(filename), "%s/maps/map0/offset", dirname2); - if (pci_parse_sysfs_value(filename, &offset) < 0) { + if (eal_parse_sysfs_value(filename, &offset) < 0) { RTE_LOG(ERR, EAL, "%s(): cannot parse offset\n", __func__); return -1; @@ -375,7 +375,7 @@ pci_uio_map_resource(struct rte_pci_device *dev) /* get mapping size */ rte_snprintf(filename, sizeof(filename), "%s/maps/map0/size", dirname2); - if (pci_parse_sysfs_value(filename, &size) < 0) { + if (eal_parse_sysfs_value(filename, &size) < 0) { RTE_LOG(ERR, EAL, "%s(): cannot parse size\n", __func__); return -1; @@ -465,37 +465,6 @@ error: return -1; } -/* parse a sysfs file containing one integer value */ -static int -pci_parse_sysfs_value(const char *filename, unsigned long *val) -{ - FILE *f; - char buf[BUFSIZ]; - char *end = NULL; - - f = fopen(filename, "r"); - if (f == NULL) { - RTE_LOG(ERR, EAL, "%s(): cannot open sysfs value %s\n", - __func__, filename); - return -1; - } - - if (fgets(buf, sizeof(buf), f) == NULL) { - RTE_LOG(ERR, EAL, "%s(): cannot read sysfs value %s\n", - __func__, filename); - fclose(f); - return -1; - } - *val = strtoul(buf, &end, 0); - if ((buf[0] == '\0') || (end == NULL) || (*end != '\n')) { - RTE_LOG(ERR, EAL, "%s(): cannot parse sysfs value %s\n", - __func__, filename); - fclose(f); - return -1; - } - fclose(f); - return 0; -} /* Scan one pci sysfs entry, and fill the devices list from it. */ static int @@ -519,7 +488,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus, /* get vendor id */ rte_snprintf(filename, sizeof(filename), "%s/vendor", dirname); - if (pci_parse_sysfs_value(filename, &tmp) < 0) { + if (eal_parse_sysfs_value(filename, &tmp) < 0) { free(dev); return -1; } @@ -527,7 +496,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus, /* get device id */ rte_snprintf(filename, sizeof(filename), "%s/device", dirname); - if (pci_parse_sysfs_value(filename, &tmp) < 0) { + if (eal_parse_sysfs_value(filename, &tmp) < 0) { free(dev); return -1; } @@ -536,7 +505,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus, /* get subsystem_vendor id */ rte_snprintf(filename, sizeof(filename), "%s/subsystem_vendor", dirname); - if (pci_parse_sysfs_value(filename, &tmp) < 0) { + if (eal_parse_sysfs_value(filename, &tmp) < 0) { free(dev); return -1; } @@ -545,7 +514,7 @@ pci_scan_one(const char *dirname, uint16_t domain, uint8_t bus, /* get subsystem_device id */ rte_snprintf(filename, sizeof(filename), "%s/subsystem_device", dirname); - if (pci_parse_sysfs_value(filename, &tmp) < 0) { + if (eal_parse_sysfs_value(filename, &tmp) < 0) { free(dev); return -1; } diff --git a/lib/librte_eal/linuxapp/eal/include/eal_fs_paths.h b/lib/librte_eal/linuxapp/eal/include/eal_filesystem.h similarity index 85% rename from lib/librte_eal/linuxapp/eal/include/eal_fs_paths.h rename to lib/librte_eal/linuxapp/eal/include/eal_filesystem.h index b43586997e..e97934ef74 100644 --- a/lib/librte_eal/linuxapp/eal/include/eal_fs_paths.h +++ b/lib/librte_eal/linuxapp/eal/include/eal_filesystem.h @@ -34,15 +34,22 @@ /** * @file - * Paths used for storing hugepage and config info for multi-process support. + * Stores functions and path defines for files and directories + * on the filesystem for Linux, that are used by the Linux EAL. */ -#ifndef _EAL_LINUXAPP_FS_PATHS_H -#define _EAL_LINUXAPP_FS_PATHS_H +#ifndef _EAL_LINUXAPP_FILESYSTEM_H +#define _EAL_LINUXAPP_FILESYSTEM_H /** Path of rte config file. */ #define RUNTIME_CONFIG_FMT "%s/.%s_config" +#include +#include +#include +#include +#include "eal_internal_cfg.h" + static const char *default_config_dir = "/var/run"; static inline const char * @@ -91,5 +98,8 @@ eal_get_hugefile_path(char *buffer, size_t buflen, const char *hugedir, int f_id /** define the default filename prefix for the %s values above */ #define HUGEFILE_PREFIX_DEFAULT "rte" +/** Function to read a single numeric value from a file on the filesystem. + * Used to read information from files on /sys */ +int eal_parse_sysfs_value(const char *filename, unsigned long *val); -#endif /* _EAL_LINUXAPP_FS_PATHS_H */ +#endif /* _EAL_LINUXAPP_FILESYSTEM_H */ -- 2.20.1