ACK: [PATCH 1/3] src/lib: add module probing helper functions
Alex Hung
alex.hung at canonical.com
Tue Nov 13 07:03:03 UTC 2018
On 2018-11-08 10:45 p.m., Colin King wrote:
> From: Colin Ian King <colin.king at canonical.com>
>
> Rather than load/unload modules with modrobe instead use direct system
> calls to perform these actions. This allows us to have finer control
> of the error handling and it is faster too.
>
> Signed-off-by: Colin Ian King <colin.king at canonical.com>
> ---
> src/lib/include/fwts.h | 1 +
> src/lib/include/fwts_modprobe.h | 29 ++++
> src/lib/src/Makefile.am | 1 +
> src/lib/src/fwts_modprobe.c | 235 ++++++++++++++++++++++++++++++++
> 4 files changed, 266 insertions(+)
> create mode 100644 src/lib/include/fwts_modprobe.h
> create mode 100644 src/lib/src/fwts_modprobe.c
>
> diff --git a/src/lib/include/fwts.h b/src/lib/include/fwts.h
> index 62834ec3..3f343ef2 100644
> --- a/src/lib/include/fwts.h
> +++ b/src/lib/include/fwts.h
> @@ -203,5 +203,6 @@
> #include "fwts_safe_mem.h"
> #include "fwts_devicetree.h"
> #include "fwts_pm_debug.h"
> +#include "fwts_modprobe.h"
>
> #endif
> diff --git a/src/lib/include/fwts_modprobe.h b/src/lib/include/fwts_modprobe.h
> new file mode 100644
> index 00000000..5a1c6e27
> --- /dev/null
> +++ b/src/lib/include/fwts_modprobe.h
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright (C) 2018 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +
> +#ifndef __FWTS_MODPROBE_H__
> +#define __FWTS_MODPROBE_H__
> +
> +#include "fwts_framework.h"
> +
> +int fwts_module_loaded(fwts_framework *fw, const char *module, bool *loaded);
> +int fwts_module_load(fwts_framework *fw, const char *module);
> +int fwts_module_unload(fwts_framework *fw, const char *module);
> +
> +#endif
> diff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am
> index 54de7f44..9858d04c 100644
> --- a/src/lib/src/Makefile.am
> +++ b/src/lib/src/Makefile.am
> @@ -92,6 +92,7 @@ libfwts_la_SOURCES = \
> fwts_log_xml.c \
> fwts_memorymap.c \
> fwts_mmap.c \
> + fwts_modprobe.c \
> fwts_multiproc.c \
> fwts_oops.c \
> fwts_pci.c \
> diff --git a/src/lib/src/fwts_modprobe.c b/src/lib/src/fwts_modprobe.c
> new file mode 100644
> index 00000000..03e3a5f1
> --- /dev/null
> +++ b/src/lib/src/fwts_modprobe.c
> @@ -0,0 +1,235 @@
> +/*
> + * Copyright (C) 2018 Canonical
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
> + *
> + */
> +#define _GNU_SOURCE
> +
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <sys/stat.h>
> +#include <sys/syscall.h>
> +#include <sys/types.h>
> +#include <dirent.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <errno.h>
> +#include <sys/utsname.h>
> +
> +#include "fwts.h"
> +
> +/*
> + * fwts_module_find()
> + * recursively search for module from the basepath start
> + * and return false if not found, and true if found. If
> + * found, the full path of the module is set in the string
> + * path.
> + */
> +static bool fwts_module_find(
> + const char *module,
> + const char *basepath,
> + char *path,
> + const size_t path_len)
> +{
> + DIR *dir;
> + struct dirent *de;
> +
> + dir = opendir(basepath);
> + if (!dir)
> + return false;
> +
> + while ((de = readdir(dir)) != NULL) {
> + char newpath[PATH_MAX];
> +
> + if (de->d_name[0] == '.')
> + continue;
> +
> + switch (de->d_type) {
> + case DT_DIR:
> + (void)snprintf(newpath, sizeof(newpath), "%s/%s",
> + basepath, de->d_name);
> + if (fwts_module_find(module, newpath, path, path_len)) {
> + (void)closedir(dir);
> + return true;
> + }
> + break;
> + case DT_REG:
> + if (!strcmp(de->d_name, module)) {
> + (void)snprintf(path, path_len, "%s/%s", basepath, module);
> + (void)closedir(dir);
> + return true;
> + }
> + break;
> + default:
> + break;
> + }
> + }
> +
> + (void)closedir(dir);
> + return false;
> +}
> +
> +/*
> + * sys_finit_module()
> + * system call wrapper for finit_module
> + */
> +static inline int sys_finit_module(
> + int fd,
> + const char *param_values,
> + int flags)
> +{
> + errno = 0;
> + return syscall(__NR_finit_module, fd, param_values, flags);
> +}
> +
> +/*
> + * sys_delete_module()
> + * system call wrapper for delete_module
> + */
> +static inline int sys_delete_module(
> + const char *name,
> + int flags)
> +{
> + errno = 0;
> + return syscall(__NR_delete_module, name, flags);
> +}
> +
> +/*
> + * fwts_module_loaded()
> + * check if module is loaded, the name (without .ko suffix) is
> + * provided in string module. Boolean loaded is set to true if
> + * the module is loaded, false otherwise. Returns FWTS_OK if
> + * all went OK, FWTS_ERROR if something went wrong.
> + */
> +int fwts_module_loaded(fwts_framework *fw, const char *module, bool *loaded)
> +{
> + FILE *fp;
> + char buffer[1024];
> +
> + *loaded = false;
> + fp = fopen("/proc/modules", "r");
> + if (!fp) {
> + fwts_log_error(fw, "Cannot open /proc/modules, errno=%d (%s)\n",
> + errno, strerror(errno));
> + return FWTS_ERROR;
> + }
> +
> + (void)memset(buffer, 0, sizeof(buffer));
> + while (fgets(buffer, sizeof(buffer) - 1, fp) != NULL) {
> + char *ptr = strchr(buffer, ' ');
> +
> + if (*ptr)
> + *ptr = '\0';
> +
> + if (!strcmp(buffer, module)) {
> + *loaded = true;
> + break;
> + }
> + }
> + (void)fclose(fp);
> +
> + return FWTS_OK;
> +}
> +
> +/*
> + * fwts_module_load()
> + * load a module. The module name (without the .ko) suffix
> + * is to provided in string module. Returns FWTS_OK if
> + * succeeded (or the module is already loaded) and FWTS_ERROR
> + * if the load failed.
> + */
> +int fwts_module_load(fwts_framework *fw, const char *module)
> +{
> + struct utsname u;
> + const size_t modlen = strlen(module);
> + char module_ko[modlen + 4];
> + char path[PATH_MAX];
> + char modpath[PATH_MAX];
> + const char *params = "";
> + int fd;
> + bool loaded = false;
> +
> + /*
> + * No need to unload if it's not already loaded
> + */
> + if (fwts_module_loaded(fw, module, &loaded) == FWTS_OK) {
> + if (loaded)
> + return FWTS_OK;
> + }
> +
> + /*
> + * Set up module root path and try to find the named module
> + */
> + if (uname(&u) < 0) {
> + fwts_log_error(fw, "Call to uname failed, errno=%d (%s)\n",
> + errno, strerror(errno));
> + return FWTS_ERROR;
> + }
> + (void)snprintf(module_ko, sizeof(module_ko), "%s.ko", module);
> + (void)snprintf(modpath, sizeof(modpath), "/lib/modules/%s", u.release);
> + if (!fwts_module_find(module_ko, modpath, path, sizeof(path))) {
> + fwts_log_error(fw, "Cannot find module %s\n", module);
> + return FWTS_ERROR;
> + }
> +
> + /*
> + * We've found it, now try and load it
> + */
> + fd = open(path, O_RDONLY);
> + if (fd < 0) {
> + fwts_log_error(fw, "Cannot open module %s, errno=%d (%s)\n",
> + path, errno, strerror(errno));
> + return FWTS_ERROR;
> + }
> + if (sys_finit_module(fd, params, 0) < 0) {
> + fwts_log_error(fw, "Cannot load module %s, errno=%d (%s)\n",
> + path, errno, strerror(errno));
> + (void)close(fd);
> + return FWTS_ERROR;
> + }
> + (void)close(fd);
> +
> + return FWTS_OK;
> +}
> +
> +/*
> + * fwts_module_unload()
> + * unload a module. The module name (without the .ko) suffix
> + * is to provided in string module. Returns FWTS_OK if
> + * succeeded (or the module is not previously loaded) and
> + * FWTS_ERROR if the unload failed.
> + */
> +int fwts_module_unload(fwts_framework *fw, const char *module)
> +{
> + bool loaded = false;
> + int ret;
> +
> + /*
> + * No need to unload if it's not already loaded
> + */
> + if (fwts_module_loaded(fw, module, &loaded) == FWTS_OK) {
> + if (!loaded)
> + return FWTS_OK;
> + }
> +
> + ret = sys_delete_module(module, O_NONBLOCK);
> + if (ret < 0) {
> + fwts_log_error(fw, "Cannot unload module %s, errno=%d (%s)\n",
> + module, errno, strerror(errno));
> + return FWTS_ERROR;
> + }
> + return FWTS_OK;
> +}
>
Acked-by: Alex Hung <alex.hung at canonical.com>
More information about the fwts-devel
mailing list