lib: sysfs parsing

Signed-off-by: Intel
This commit is contained in:
Intel 2012-12-20 00:00:00 +01:00 committed by Thomas Monjalon
parent 3fc5ca2f63
commit 32832fc6c0
9 changed files with 275 additions and 49 deletions

View File

@ -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)

View File

@ -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 = {

View File

@ -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

210
app/test/test_eal_fs.c Normal file
View File

@ -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 <cmdline_parse.h>
#include "test.h"
#ifndef RTE_EXEC_ENV_BAREMETAL
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 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

View File

@ -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).

View File

@ -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;
}

View File

@ -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"
/**

View File

@ -66,6 +66,7 @@
#include <rte_debug.h>
#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 @@ pci_parse_sysfs_resource(const char *filename, struct rte_pci_device *dev)
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;
}

View File

@ -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 <stdint.h>
#include <limits.h>
#include <unistd.h>
#include <rte_string_fns.h>
#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 */