/* * 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 #include "cpuplugd.h" /* * Return overall number of available cpus. This does not necessarily * mean that those are currently online */ int get_numcpus() { int i; char path[PATH_MAX]; int number = 0; for (i = 0; ; i++) { /* check whether file exists and is readable */ sprintf(path, "/sys/devices/system/cpu/cpu%d/online", i); if (access(path, R_OK) == 0) number++; else break; } return number; } /* * Return number of online cpus */ int get_num_online_cpus() { FILE *filp; int i; char path[PATH_MAX]; int status = 0; int value_of_onlinefile, rc; 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) 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); } return status; } /* * Enable a certain cpu */ int hotplug(int cpuid) { FILE *filp; char path[PATH_MAX]; int status, rc; 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; } } else { cpuplugd_error("hotplugging cpu with id %d failed\n", cpuid); return -1; } return -1; } /* * Disable a certain cpu */ int hotunplug(int cpuid) { FILE *filp; int state, rc; int retval = -1; char path[PATH_MAX]; 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; } else { cpuplugd_error("unplugging cpu with id %d failed\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; fclose(filp); } } return retval; } /* * Cleanup method. If the daemon is stopped, we (re)activate all cpus */ void reactivate_cpus() { /* * Only enable the number of cpus which where * available at daemon startup time */ int cpuid, nc; 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 */ if (num_cpu_start == 0) return; while (get_num_online_cpus() != num_cpu_start && cpuid < get_numcpus()) { nc = get_num_online_cpus(); if (nc == num_cpu_start) return; if (nc > num_cpu_start && is_online(cpuid) == 1) hotunplug(cpuid); if (nc < num_cpu_start && is_online(cpuid) == 0) hotplug(cpuid); cpuid++; } } /* * 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; }