mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
Cpuplugd checks for system polarization before adjusting cpu hotplug states. Currently, if the sysfs attribute for polarization is not present cpuplugd does not make any adjustments. Add a new polarization type PLR_NONE to reflect systems with no polarization state and allow cpuplugd to adjust cpu hotplugging. Signed-off-by: Mete Durlu <meted@linux.ibm.com> Reviewed-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com> Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
255 lines
6.1 KiB
C
255 lines
6.1 KiB
C
/*
|
|
* cpuplugd - Linux for System z Hotplug Daemon
|
|
*
|
|
* CPU hotplug functions
|
|
*
|
|
* Copyright IBM Corp. 2007, 2017
|
|
*
|
|
* s390-tools is free software; you can redistribute it and/or modify
|
|
* it under the terms of the MIT license. See LICENSE for details.
|
|
*/
|
|
|
|
#include <limits.h>
|
|
#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)
|
|
|
|
static int get_sysfs_attribute_cpu_count(char *path)
|
|
{
|
|
char cpu_list[CPU_LIST_LEN];
|
|
int number, start, end;
|
|
char *sub_list;
|
|
|
|
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++;
|
|
}
|
|
sub_list = strtok(NULL, ",");
|
|
}
|
|
return number;
|
|
}
|
|
|
|
/*
|
|
* 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_numcpus(void)
|
|
{
|
|
int number;
|
|
char *path;
|
|
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* get_polarization() - return system polarization
|
|
*/
|
|
int get_polarization(void)
|
|
{
|
|
int polarization;
|
|
char *path;
|
|
|
|
path = util_path_sysfs("devices/system/cpu/dispatching");
|
|
if (!util_path_exists(path))
|
|
return PLR_NONE;
|
|
if (util_file_read_i(&polarization, NUM_BASE, path) < 0) {
|
|
polarization = -1;
|
|
cpuplugd_debug("failed to read system polarization\n");
|
|
}
|
|
free(path);
|
|
return polarization;
|
|
}
|
|
|
|
/*
|
|
* 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;
|
|
}
|
|
|
|
/*
|
|
* hotplug_one_cpu() - perform hotplugging on the first available cpu
|
|
*/
|
|
int hotplug_one_cpu(void)
|
|
{
|
|
struct dirent **cpu_dir;
|
|
int cpuid, count, i, rc;
|
|
char *path;
|
|
|
|
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);
|
|
}
|
|
}
|
|
util_scandir_free(cpu_dir, count);
|
|
free(path);
|
|
return rc;
|
|
}
|
|
|
|
/*
|
|
* hotunplug_one_cpu() - perform hotunplugging on the first available cpu
|
|
*/
|
|
int hotunplug_one_cpu(void)
|
|
{
|
|
struct dirent **cpu_dir;
|
|
int cpuid, count, i, rc;
|
|
char *path;
|
|
|
|
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);
|
|
}
|
|
}
|
|
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)
|
|
{
|
|
struct dirent **cpu_dir;
|
|
int cpuid, nc, count, i;
|
|
char *path;
|
|
|
|
/*
|
|
* 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;
|
|
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 (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 &&
|
|
get_cpu_attribute(cpuid, "online") == CPU_OFFLINE)
|
|
hotplug(cpuid);
|
|
}
|
|
util_scandir_free(cpu_dir, count);
|
|
free(path);
|
|
}
|
|
|