2016-06-08 22:36:38 +02:00
|
|
|
/** Linux kernel related functions.
|
2015-09-17 00:55:20 +02:00
|
|
|
*
|
|
|
|
* @author Steffen Vogel <stvogel@eonerc.rwth-aachen.de>
|
2017-03-03 20:20:13 -04:00
|
|
|
* @copyright 2017, Institute for Automation of Complex Power Systems, EONERC
|
2017-04-27 12:56:43 +02:00
|
|
|
* @license GNU General Public License (version 3)
|
|
|
|
*
|
|
|
|
* VILLASnode
|
|
|
|
*
|
|
|
|
* 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 3 of the License, or
|
|
|
|
* any later version.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* 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.
|
2017-05-05 19:24:16 +00:00
|
|
|
*
|
2017-04-27 12:56:43 +02:00
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
2015-09-17 00:55:20 +02:00
|
|
|
*********************************************************************************/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
2016-03-18 12:38:28 +01:00
|
|
|
|
2015-09-17 00:55:20 +02:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/utsname.h>
|
2016-03-18 12:38:28 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2017-12-09 02:19:28 +08:00
|
|
|
#include <villas/utils.h>
|
|
|
|
#include <villas/config.h>
|
|
|
|
#include <villas/kernel/kernel.h>
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2017-07-24 19:21:57 +02:00
|
|
|
int kernel_get_cacheline_size()
|
|
|
|
{
|
|
|
|
#ifdef __linux__
|
|
|
|
return sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
|
|
|
|
#else
|
|
|
|
return 64; /** @todo fixme */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __linux__
|
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
int kernel_module_set_param(const char *module, const char *param, const char *value)
|
2015-09-17 00:55:20 +02:00
|
|
|
{
|
2016-03-18 12:38:28 +01:00
|
|
|
FILE *f;
|
|
|
|
char fn[256];
|
|
|
|
|
|
|
|
snprintf(fn, sizeof(fn), "%s/module/%s/parameters/%s", SYSFS_PATH, module, param);
|
|
|
|
f = fopen(fn, "w");
|
2016-06-13 17:19:47 +02:00
|
|
|
if (!f)
|
2016-03-18 12:38:28 +01:00
|
|
|
serror("Failed set parameter %s for kernel module %s to %s", module, param, value);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-05-05 19:09:32 +00:00
|
|
|
debug(LOG_KERNEL | 5, "Set parameter %s of kernel module %s to %s", module, param, value);
|
2016-06-13 17:19:47 +02:00
|
|
|
fprintf(f, "%s", value);
|
|
|
|
fclose(f);
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
return 0;
|
2015-09-17 00:55:20 +02:00
|
|
|
}
|
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
int kernel_module_load(const char *module)
|
2015-09-17 00:55:20 +02:00
|
|
|
{
|
2016-03-18 12:38:28 +01:00
|
|
|
int ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
ret = kernel_module_loaded(module);
|
|
|
|
if (!ret) {
|
2017-05-05 19:09:32 +00:00
|
|
|
debug(LOG_KERNEL | 5, "Kernel module %s already loaded...", module);
|
2016-03-18 12:38:28 +01:00
|
|
|
return 0;
|
|
|
|
}
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
pid_t pid = fork();
|
|
|
|
switch (pid) {
|
|
|
|
case -1: // error
|
|
|
|
return -1;
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
case 0: // child
|
|
|
|
execlp("modprobe", "modprobe", module, (char *) 0);
|
2017-05-05 19:09:32 +00:00
|
|
|
exit(EXIT_FAILURE); // exec never returns
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
default:
|
2017-05-05 19:09:32 +00:00
|
|
|
wait(&ret);
|
2015-09-17 00:55:20 +02:00
|
|
|
|
2017-05-05 19:09:32 +00:00
|
|
|
return kernel_module_loaded(module);
|
|
|
|
}
|
2015-09-17 00:55:20 +02:00
|
|
|
}
|
|
|
|
|
2016-03-18 12:38:28 +01:00
|
|
|
int kernel_module_loaded(const char *module)
|
2015-09-19 12:14:35 +02:00
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int ret = -1;
|
|
|
|
char *line = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
|
2015-09-19 15:28:28 +02:00
|
|
|
f = fopen(PROCFS_PATH "/modules", "r");
|
|
|
|
if (!f)
|
2015-09-19 12:14:35 +02:00
|
|
|
return -1;
|
|
|
|
|
|
|
|
while (getline(&line, &len, f) >= 0) {
|
|
|
|
if (strstr(line, module) == line) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(line);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-04-02 02:33:20 +02:00
|
|
|
int kernel_get_version(struct version *v)
|
2016-03-18 12:38:28 +01:00
|
|
|
{
|
|
|
|
struct utsname uts;
|
|
|
|
|
|
|
|
if (uname(&uts) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2017-04-02 02:33:20 +02:00
|
|
|
if (version_parse(uts.release, v))
|
2016-03-18 12:38:28 +01:00
|
|
|
return -1;
|
|
|
|
|
2017-04-02 02:33:20 +02:00
|
|
|
return 0;
|
2016-03-18 12:38:28 +01:00
|
|
|
}
|
|
|
|
|
2016-06-26 15:29:07 +02:00
|
|
|
int kernel_get_cmdline_param(const char *param, char *buf, size_t len)
|
2016-03-18 12:38:28 +01:00
|
|
|
{
|
2016-06-26 15:29:07 +02:00
|
|
|
int ret;
|
|
|
|
char cmdline[512];
|
2016-03-18 12:38:28 +01:00
|
|
|
|
|
|
|
FILE *f = fopen(PROCFS_PATH "/cmdline", "r");
|
|
|
|
if (!f)
|
|
|
|
return -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-26 15:29:07 +02:00
|
|
|
if (!fgets(cmdline, sizeof(cmdline), f))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
char *tok = strtok(cmdline, " \t");
|
|
|
|
do {
|
|
|
|
char key[128], value[128];
|
|
|
|
|
|
|
|
ret = sscanf(tok, "%127[^=]=%127s", key, value);
|
|
|
|
if (ret >= 1) {
|
|
|
|
if (ret >= 2)
|
|
|
|
debug(30, "Found kernel param: %s=%s", key, value);
|
|
|
|
else
|
|
|
|
debug(30, "Found kernel param: %s", key);
|
|
|
|
|
|
|
|
if (strcmp(param, key) == 0) {
|
|
|
|
if (ret >= 2 && buf)
|
2018-04-04 08:53:00 +02:00
|
|
|
snprintf(buf, len, "%s", value);
|
2016-06-26 15:29:07 +02:00
|
|
|
|
|
|
|
return 0; /* found */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} while((tok = strtok(NULL, " \t")));
|
|
|
|
|
|
|
|
out:
|
2016-06-08 22:44:44 +02:00
|
|
|
fclose(f);
|
2016-03-18 12:38:28 +01:00
|
|
|
|
2016-06-26 15:29:07 +02:00
|
|
|
return -1; /* not found or error */
|
2016-06-08 22:30:30 +02:00
|
|
|
}
|
2016-06-08 22:36:38 +02:00
|
|
|
|
2017-04-02 00:14:17 +02:00
|
|
|
int kernel_get_page_size()
|
|
|
|
{
|
|
|
|
return sysconf(_SC_PAGESIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* There is no sysconf interface to get the hugepage size */
|
|
|
|
int kernel_get_hugepage_size()
|
|
|
|
{
|
|
|
|
char *key, *value, *unit, *line = NULL;
|
2017-04-02 02:33:55 +02:00
|
|
|
int sz = -1;
|
2017-04-02 00:14:17 +02:00
|
|
|
size_t len = 0;
|
|
|
|
FILE *f;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-04-02 00:14:17 +02:00
|
|
|
f = fopen(PROCFS_PATH "/meminfo", "r");
|
|
|
|
if (!f)
|
|
|
|
return -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-04-02 00:14:17 +02:00
|
|
|
while (getline(&line, &len, f) != -1) {
|
|
|
|
key = strtok(line, ": ");
|
|
|
|
value = strtok(NULL, " ");
|
|
|
|
unit = strtok(NULL, "\n");
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-04-02 02:33:55 +02:00
|
|
|
if (!strcmp(key, "Hugepagesize") && !strcmp(unit, "kB")) {
|
|
|
|
sz = strtoul(value, NULL, 10) * 1024;
|
|
|
|
break;
|
|
|
|
}
|
2017-04-02 00:14:17 +02:00
|
|
|
}
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2017-04-02 13:03:31 +02:00
|
|
|
free(line);
|
2017-04-02 02:33:55 +02:00
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return sz;
|
2017-04-02 00:14:17 +02:00
|
|
|
}
|
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
int kernel_get_nr_hugepages()
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
int nr, ret;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
f = fopen(PROCFS_PATH "/sys/vm/nr_hugepages", "r");
|
|
|
|
if (!f)
|
|
|
|
serror("Failed to open %s", PROCFS_PATH "/sys/vm/nr_hugepages");
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
ret = fscanf(f, "%d", &nr);
|
|
|
|
if (ret != 1)
|
|
|
|
nr = -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
fclose(f);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
return nr;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kernel_set_nr_hugepages(int nr)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
f = fopen(PROCFS_PATH "/sys/vm/nr_hugepages", "w");
|
|
|
|
if (!f)
|
|
|
|
serror("Failed to open %s", PROCFS_PATH "/sys/vm/nr_hugepages");
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
fprintf(f, "%d\n", nr);
|
|
|
|
fclose(f);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-11-20 02:45:16 -05:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-06-08 22:44:44 +02:00
|
|
|
#if 0
|
2017-04-02 02:33:55 +02:00
|
|
|
int kernel_has_cap(cap_value_t cap)
|
2016-06-08 22:44:44 +02:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
cap_t caps;
|
|
|
|
cap_flag_value_t value;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-08 22:44:44 +02:00
|
|
|
caps = cap_get_proc();
|
|
|
|
if (caps == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
ret = cap_get_proc(caps);
|
|
|
|
if (ret == -1)
|
|
|
|
return -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-08 22:44:44 +02:00
|
|
|
ret = cap_get_flag(caps, cap, CAP_EFFECTIVE, &value);
|
|
|
|
if (ret == -1)
|
|
|
|
return -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
|
|
|
ret = cap_free(caps);
|
2016-06-08 22:44:44 +02:00
|
|
|
if (ret)
|
|
|
|
return -1;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-08 22:44:44 +02:00
|
|
|
return value == CAP_SET ? 0 : -1;
|
|
|
|
}
|
2016-06-13 17:16:45 +02:00
|
|
|
#endif
|
|
|
|
|
2018-07-03 20:43:05 +02:00
|
|
|
int kernel_irq_setaffinity(unsigned irq, uintmax_t aff, uintmax_t *old)
|
2016-06-13 17:16:45 +02:00
|
|
|
{
|
|
|
|
char fn[64];
|
|
|
|
FILE *f;
|
2016-10-10 23:09:09 +02:00
|
|
|
int ret = 0;
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-13 17:16:45 +02:00
|
|
|
snprintf(fn, sizeof(fn), "/proc/irq/%u/smp_affinity", irq);
|
2017-05-05 19:24:16 +00:00
|
|
|
|
2016-06-13 17:16:45 +02:00
|
|
|
f = fopen(fn, "w+");
|
|
|
|
if (!f)
|
|
|
|
return -1; /* IRQ does not exist */
|
|
|
|
|
|
|
|
if (old)
|
2016-10-10 23:09:09 +02:00
|
|
|
ret = fscanf(f, "%jx", old);
|
2016-06-13 17:16:45 +02:00
|
|
|
|
2018-07-03 20:43:05 +02:00
|
|
|
fprintf(f, "%jx", aff);
|
2016-06-13 17:16:45 +02:00
|
|
|
fclose(f);
|
|
|
|
|
2016-10-10 23:09:09 +02:00
|
|
|
return ret;
|
2016-06-13 17:16:45 +02:00
|
|
|
}
|
2017-07-24 19:21:57 +02:00
|
|
|
|
|
|
|
#endif /* __linux__ */
|