From c91d172c99e9642bdf5ccc9b5111ec70c665cff2 Mon Sep 17 00:00:00 2001 From: Mete Durlu Date: Thu, 23 May 2024 10:51:15 +0200 Subject: [PATCH] cpuplugd/cpu: Rework CPU management functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Simplify the cpu management parts of cpuplugd code by introducing functions from libutil and rework some logic to drop some assumptions about how kernel assigns cpuids. Right now cpuplugd assumes that the cpuids are always sequential and there are no gaps in between, however kernel does not guarantee that. Make cpuplugd compliant by traversing cpu sysfs entries instead. Reviewed-by: Steffen Eiden Reviewed-by: Gerald Schaefer Signed-off-by: Mete Durlu Signed-off-by: Jan Höppner --- cpuplugd/Makefile | 4 +- cpuplugd/config.c | 29 +--- cpuplugd/cpu.c | 343 +++++++++++++++++++++++--------------------- cpuplugd/cpuplugd.h | 9 +- cpuplugd/main.c | 34 +---- 5 files changed, 195 insertions(+), 224 deletions(-) diff --git a/cpuplugd/Makefile b/cpuplugd/Makefile index 916638d1..20d964dd 100644 --- a/cpuplugd/Makefile +++ b/cpuplugd/Makefile @@ -4,9 +4,11 @@ all: cpuplugd LDLIBS += -lm +libs = $(rootdir)/libutil/libutil.a + OBJECTS = daemon.o cpu.o info.o terms.o config.o main.o getopt.o mem.o -cpuplugd: $(OBJECTS) +cpuplugd: $(OBJECTS) $(libs) $(LINK) $(ALL_LDFLAGS) $^ $(LDLIBS) -o $@ clean: diff --git a/cpuplugd/config.c b/cpuplugd/config.c index 4addff1b..e48a3913 100644 --- a/cpuplugd/config.c +++ b/cpuplugd/config.c @@ -211,7 +211,6 @@ void parse_configfile(char *file) */ void check_config() { - int cpuid; int lpar_status; lpar_status = check_lpar(); @@ -275,33 +274,17 @@ void check_config() get_numcpus() >= cfg.cpu_min) { cpuplugd_debug("The number of online cpus is below " "the minimum and will be increased.\n"); - cpuid = 0; - while (get_num_online_cpus() < cfg.cpu_min && - cpuid < get_numcpus()) { - if (is_online(cpuid) == 1) { - cpuid++; - continue; - } - cpuplugd_debug("cpu with id %d is currently offline " - "and will be enabled\n", cpuid); - hotplug(cpuid); - cpuid++; + while (get_num_online_cpus() < cfg.cpu_min) { + if (hotplug_one_cpu()) + break; } } if (get_num_online_cpus() > cfg.cpu_max) { cpuplugd_debug("The number of online cpus is above the maximum" " and will be decreased.\n"); - cpuid = 0; - while (get_num_online_cpus() > cfg.cpu_max && - cpuid < get_numcpus()) { - if (is_online(cpuid) != 1) { - cpuid++; - continue; - } - cpuplugd_debug("cpu with id %d is currently online " - "and will be disabled\n", cpuid); - hotunplug(cpuid); - cpuid++; + while (get_num_online_cpus() > cfg.cpu_max) { + if (hotunplug_one_cpu()) + break; } } if (cfg.cpu_min > get_numcpus()) diff --git a/cpuplugd/cpu.c b/cpuplugd/cpu.c index 03f48ab1..54a6f349 100644 --- a/cpuplugd/cpu.c +++ b/cpuplugd/cpu.c @@ -12,217 +12,226 @@ #include #include "cpuplugd.h" +#define NUM_BASE (10) +#define CPU_OFFLINE (0) +#define CPU_ONLINE (1) +#define CPU_DECONFIGURED (0) +#define CPU_CONFIGURED (1) +#define CPU_LIST_LEN (4096) -/* - * Return overall number of available cpus. This does not necessarily - * mean that those are currently online - */ -int get_numcpus() +static int get_sysfs_attribute_cpu_count(char *path) { - int i; - char path[PATH_MAX]; - int number = 0; + char cpu_list[CPU_LIST_LEN]; + int number, start, end; + char *sub_list; - for (i = 0; ; i++) { - /* check whether file exists and is readable */ - sprintf(path, "/sys/devices/system/cpu/cpu%d", i); - if (access(path, R_OK) == 0) + if (util_file_read_line(cpu_list, sizeof(cpu_list), path)) + cpuplugd_exit("Cannot open %s file: %s\n", path, strerror(errno)); + number = 0; + sub_list = strtok(cpu_list, ","); + while (sub_list) { + if (strchr(sub_list, '-')) { + if (sscanf(sub_list, "%d-%d", &start, &end) != 2) + cpuplugd_exit("Malformed content of %s: %s\n", path, sub_list); + number += (end - start) + 1; + } else { number++; - else - break; + } + sub_list = strtok(NULL, ","); } return number; } /* - * Return number of online cpus + * get_numcpus() - return number of present cpus by sysfs' + * cpu/present attribute. + * This number represents the total number of usable cpus, + * this includes offline or deconfigured cpus as well. */ -int get_num_online_cpus() +int get_numcpus(void) { - FILE *filp; - int i; - char path[PATH_MAX]; - int status = 0; - int value_of_onlinefile, rc; + int number; + char *path; - for (i = 0; i < get_numcpus(); i++) { - /* check wether file exists and is readable */ - sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i); - if (access(path, R_OK) != 0) { - status++; - continue; - } - filp = fopen(path, "r"); - if (!filp) - cpuplugd_exit("Cannot open cpu online file: " - "%s\n", strerror(errno)); - else { - rc = fscanf(filp, "%d", &value_of_onlinefile); - if (rc != 1) - cpuplugd_exit("Cannot read cpu online file: " - "%s\n", strerror(errno)); - if (value_of_onlinefile == 1) - status++; - } - fclose(filp); + path = util_path_sysfs("devices/system/cpu/present"); + number = get_sysfs_attribute_cpu_count(path); + free(path); + if (number <= 0) + cpuplugd_exit("number of present cpus (%d) <= 0\n", number); + return number; +} + +/* + * get_num_online_cpus() - return number of online cpus + * by parsing sysfs cpu/online attribute + */ +int get_num_online_cpus(void) +{ + int number; + char *path; + + path = util_path_sysfs("devices/system/cpu/online"); + number = get_sysfs_attribute_cpu_count(path); + free(path); + if (number <= 0) + cpuplugd_exit("number of online cpus (%d) <= 0\n", number); + return number; +} + +/* + * is_cpu_hotpluggable() - check if cpuhotplug operations are supported + * for the given cpu. + */ +static int is_cpu_hotpluggable(int cpuid) +{ + char *path; + int rc; + + path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid); + rc = util_path_exists(path); + free(path); + return rc; +} + +/* + * hotplug() - perform cpu hotplug on given cpuid + */ +static int hotplug(int cpuid) +{ + char *path; + int rc; + + path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid); + rc = util_file_write_l(CPU_ONLINE, NUM_BASE, path); + if (rc < 0) + cpuplugd_debug("failed to enable cpu with id %d\n", cpuid); + free(path); + return rc; +} + +/* + * hotunplug() - perform cpu hotunplug on given cpuid + */ +static int hotunplug(int cpuid) +{ + char *path; + int rc; + + path = util_path_sysfs("devices/system/cpu/cpu%d/online", cpuid); + rc = util_file_write_l(CPU_OFFLINE, NUM_BASE, path); + if (rc < 0) + cpuplugd_debug("failed to disable cpu with id %d\n", cpuid); + free(path); + return rc; +} + +/* + * get_cpu_attribute() - get a certain cpu's selected attribute + */ +static int get_cpu_attribute(int cpuid, char *attribute) +{ + int status; + char *path; + + path = util_path_sysfs("devices/system/cpu/cpu%d/%s", cpuid, attribute); + if (util_file_read_i(&status, NUM_BASE, path) < 0) { + status = -1; + cpuplugd_debug("failed to read %s status of cpu with id %d\n", attribute, cpuid); } + free(path); return status; } /* - * Enable a certain cpu + * hotplug_one_cpu() - perform hotplugging on the first available cpu */ -int hotplug(int cpuid) +int hotplug_one_cpu(void) { - FILE *filp; - char path[PATH_MAX]; - int status, rc; + struct dirent **cpu_dir; + int cpuid, count, i, rc; + char *path; - sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid); - if (access(path, W_OK) == 0) { - filp = fopen(path, "w"); - if (!filp) - cpuplugd_exit("Cannot open cpu online file: %s\n", - strerror(errno)); - fprintf(filp, "1"); - fclose(filp); - /* - * check if the attempt to enable the cpus really worked - */ - filp = fopen(path, "r"); - rc = fscanf(filp, "%d", &status); - if (rc != 1) - cpuplugd_exit("Cannot open cpu online file: %s\n", - strerror(errno)); - fclose(filp); - if (status == 1) { - cpuplugd_debug("cpu with id %d enabled\n", cpuid); - return 1; - } else { - cpuplugd_debug("failed to enable cpu with id %d\n", - cpuid); - return -1; + rc = -1; + path = util_path_sysfs("devices/system/cpu/"); + count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*"); + for (i = 0; (i < count) && (rc != 0); i++) { + if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1) + cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name); + if (!is_cpu_hotpluggable(cpuid)) + continue; + if (get_cpu_attribute(cpuid, "configure") == CPU_CONFIGURED && + get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) { + cpuplugd_debug("cpu%d will be enabled", cpuid); + rc = hotplug(cpuid); } } - cpuplugd_debug("cpu with id %d cannot be hotplugged\n", cpuid); - return -1; + util_scandir_free(cpu_dir, count); + free(path); + return rc; } /* - * Disable a certain cpu + * hotunplug_one_cpu() - perform hotunplugging on the first available cpu */ -int hotunplug(int cpuid) +int hotunplug_one_cpu(void) { - FILE *filp; - int state, rc; - int retval = -1; - char path[PATH_MAX]; + struct dirent **cpu_dir; + int cpuid, count, i, rc; + char *path; - state = -1; - sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid); - if (access(path, W_OK) == 0) { - filp = fopen(path, "w"); - fprintf(filp, "0"); - fclose(filp); - /* - * Check if the attempt to enable the cpus really worked - */ - filp = fopen(path, "r"); - rc = fscanf(filp, "%d", &state); - if (rc != 1) - cpuplugd_error("Failed to disable cpu with id %d\n", - cpuid); - fclose(filp); - if (state == 0) - return 1; - } - cpuplugd_debug("cpu with id %d cannot be hotunplugged\n", cpuid); - return retval; -} - -/* - * Check if a certain cpu is currently online - */ -int is_online(int cpuid) -{ - FILE *filp; - int state; - int retval, rc; - char path[PATH_MAX]; - - retval = -1; - sprintf(path, "/sys/devices/system/cpu/cpu%d/online", cpuid); - if (access(path, R_OK) == 0) { - filp = fopen(path, "r"); - rc = fscanf(filp, "%d", &state); - if (rc == 1) { - if (state == 1) - retval = 1; - if (state == 0) - retval = 0; + rc = -1; + path = util_path_sysfs("devices/system/cpu/"); + count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*"); + for (i = 0; (i < count) && (rc != 0); i++) { + if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1) + cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name); + if (!is_cpu_hotpluggable(cpuid)) + continue; + if (get_cpu_attribute(cpuid, "online") == CPU_ONLINE) { + cpuplugd_debug("cpu%d will be disabled\n", cpuid); + rc = hotunplug(cpuid); } - fclose(filp); - } else { - retval = 1; } - return retval; + util_scandir_free(cpu_dir, count); + free(path); + return rc; } /* * Cleanup method. If the daemon is stopped, we (re)activate all cpus */ -void reactivate_cpus() +void reactivate_cpus(void) { - /* - * Only enable the number of cpus which where - * available at daemon startup time - */ - int cpuid, nc; + struct dirent **cpu_dir; + int cpuid, nc, count, i; + char *path; - cpuid = 0; /* suppress verbose messages on exit */ debug = 0; - /* - * We check for num_cpu_start != 0 because we might want to - * clean up, before we queried for the number on cpus at - * startup - */ + /* + * Only enable the number of cpus which where available at + * daemon startup time by checking num_cpu_start. + * We check for num_cpu_start != 0 because we might want to + * clean up, before we queried for the number on cpus at + * startup + */ if (num_cpu_start == 0) return; - while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) { + nc = 0; + path = util_path_sysfs("devices/system/cpu/"); + count = util_scandir(&cpu_dir, alphasort, path, "cpu[0-9]*"); + for (i = 0; (i < count) && (nc != num_cpu_start); i++) { nc = get_num_online_cpus(); - if (nc == num_cpu_start) - return; - if (nc > num_cpu_start && is_online(cpuid) == 1) + if (sscanf(cpu_dir[i]->d_name, "cpu%d", &cpuid) != 1) + cpuplugd_exit("Malformed content of %s: %s\n", path, cpu_dir[i]->d_name); + if (nc > num_cpu_start && + get_cpu_attribute(cpuid, "online") == CPU_ONLINE) hotunplug(cpuid); - if (nc < num_cpu_start && is_online(cpuid) == 0) + if (nc < num_cpu_start && + get_cpu_attribute(cpuid, "online") == CPU_OFFLINE) hotplug(cpuid); - cpuid++; } + util_scandir_free(cpu_dir, count); + free(path); } -/* - * In kernels > 2.6.24 cpus can be deconfigured. The following functions is used - * to check if a certain cpus is in a deconfigured state. - */ -int cpu_is_configured(int cpuid) -{ - FILE *filp; - int retval, state, rc; - char path[4096]; - - retval = -1; - sprintf(path, "/sys/devices/system/cpu/cpu%d/configure", cpuid); - if (access(path, R_OK) == 0) { - filp = fopen(path, "r"); - rc = fscanf(filp, "%d", &state); - if (rc == 1) { - if (state == 1) - retval = 1; - if (state == 0) - retval = 0; - } - fclose(filp); - } - return retval; -} diff --git a/cpuplugd/cpuplugd.h b/cpuplugd/cpuplugd.h index 93a87a03..2b06cd10 100644 --- a/cpuplugd/cpuplugd.h +++ b/cpuplugd/cpuplugd.h @@ -23,6 +23,9 @@ #include #include "lib/util_base.h" +#include "lib/util_path.h" +#include "lib/util_file.h" +#include "lib/util_scandir.h" #include "lib/zt_common.h" #define NAME "cpuplugd" @@ -190,9 +193,8 @@ void proc_cpu_read(char *procinfo); unsigned long proc_read_size(char *path); char *get_var_rvalue(char *var_name); void cleanup_cmm(void); -int hotplug(int cpuid); -int hotunplug(int cpuid); -int is_online(int cpuid); +int hotplug_one_cpu(void); +int hotunplug_one_cpu(void); long get_cmmpages_size(); void parse_options(int argc, char **argv); void check_if_started_twice(); @@ -204,7 +206,6 @@ int check_cmmfiles(void); void check_config(); void set_cmm_pages(long size); int check_lpar(); -int cpu_is_configured(int cpuid); void setup_history(void); diff --git a/cpuplugd/main.c b/cpuplugd/main.c index d889d0bc..658ca91a 100644 --- a/cpuplugd/main.c +++ b/cpuplugd/main.c @@ -77,7 +77,7 @@ static void eval_cpu_rules(void) { double diffs[CPUSTATS], diffs_total, percent_factor; char *procinfo_current, *procinfo_prev; - int cpu, nr_cpus, on_off; + int nr_cpus, on_off; nr_cpus = get_numcpus(); procinfo_current = cpustat + history_current * cpustat_size; @@ -172,40 +172,16 @@ static void eval_cpu_rules(void) cpuplugd_debug("maximum cpu limit is reached\n"); return; } - /* try to find a offline cpu */ - for (cpu = 0; cpu < nr_cpus; cpu++) - if (is_online(cpu) == 0 && cpu_is_configured(cpu) != 0) - break; - if (cpu < nr_cpus) { - cpuplugd_debug("cpu with id %d is currently offline " - "and will be enabled\n", cpu); - if (hotplug(cpu) == -1) - cpuplugd_debug("unable to find a cpu which " - "can be enabled\n"); - } else { - /* - * In case we tried to enable a cpu but this failed. - * This is the case if a cpu is deconfigured - */ - cpuplugd_debug("unable to find a cpu which can " - "be enabled\n"); - } + if (hotplug_one_cpu()) + cpuplugd_debug("unable to find a cpu which can be enabled\n"); } else if (on_off < 0) { /* check cpu nr limit */ if (symbols.onumcpus <= cfg.cpu_min) { cpuplugd_debug("minimum cpu limit is reached\n"); return; } - /* try to find a online cpu */ - for (cpu = get_numcpus() - 1; cpu >= 0; cpu--) { - if (is_online(cpu) != 0) - break; - } - if (cpu > 0) { - cpuplugd_debug("cpu with id %d is currently online " - "and will be disabled\n", cpu); - hotunplug(cpu); - } + if (hotunplug_one_cpu()) + cpuplugd_debug("unable to find a cpu which can be disabled\n"); } }