From 9bce0b3b5dba0246ccc998186b99f1c9208a9602 Mon Sep 17 00:00:00 2001 From: Unsung Lee Date: Mon, 21 Feb 2022 12:57:57 +0900 Subject: [PATCH] Parse 'PerProcess' section Change-Id: If58a8ef63fc88acdb3a9e726068b6697304b7e0f Signed-off-by: Unsung Lee --- src/common/cgroup/cgroup.h | 2 - src/common/config-parser.c | 297 ++++++++++++++++++++- src/common/config-parser.h | 38 ++- src/common/proc-common.h | 31 +++ src/common/util.h | 2 + src/process/watchdog/proc-watchdog.c | 7 +- .../memory/vmpressure-lowmem-handler.c | 2 +- src/resourced/main.c | 8 + 8 files changed, 377 insertions(+), 10 deletions(-) diff --git a/src/common/cgroup/cgroup.h b/src/common/cgroup/cgroup.h index 7c43d0c..877f6aa 100644 --- a/src/common/cgroup/cgroup.h +++ b/src/common/cgroup/cgroup.h @@ -50,8 +50,6 @@ extern "C" { #define CGROUP_PER_PROCESS_NAME "" #define CGROUP_GROUP_NAME "" -#define CGROUP_VIP_LIST_DIR RD_CONFIG_PATH"/limiter.conf.d" -#define CGROUP_VIP_CONF_SUFFIX ".conf" #define CGROUP_DEFAULT_USE_HIERARCHY false /* diff --git a/src/common/config-parser.c b/src/common/config-parser.c index 566d900..b6b85b5 100644 --- a/src/common/config-parser.c +++ b/src/common/config-parser.c @@ -25,8 +25,303 @@ #include "util.h" #include "trace.h" #include "config-parser.h" +#include "proc-common.h" -#define MAX_SECTION 64 +#define MAX_SECTION 64 +#define CPU_INIT_PRIO 100 + +static GSList *app_conf_info_list; +static GSList *service_conf_info_list; + +static struct proc_conf_info* process_exist(const char *name, enum proc_type proc_type) +{ + GSList *iter; + bool found = false; + struct proc_conf_info *pci = NULL; + + if (proc_type != APP_TYPE && proc_type != SERVICE_TYPE) + return pci; + + gslist_for_each_item(iter, + proc_type == APP_TYPE ? app_conf_info_list : service_conf_info_list) { + pci = (struct proc_conf_info *)iter->data; + if (!strncmp(pci->name, name, strlen(name)+1)) { + found = true; + break; + } + } + + if (!found) + pci = NULL; + + return pci; +} + +static int vendor_config(struct parse_result *result, void *user_data) +{ + int *config_type = (int *)user_data; + static struct proc_conf_info *pci = NULL; + + if (!result || !user_data) + return RESOURCED_ERROR_INVALID_PARAMETER; + + if (strncmp(result->section, PER_PROCESS_SECTION_CONF, strlen(PER_PROCESS_SECTION_CONF)+1)) + return RESOURCED_ERROR_NONE; + + if (!strncmp(result->name, SERVICE_NAME_CONF, strlen(SERVICE_NAME_CONF)+1) || + !strncmp(result->name, APP_NAME_CONF, strlen(APP_NAME_CONF)+1)) { + pci = process_exist(result->value, result->name[0] == 'A' ? APP_TYPE : SERVICE_TYPE); + if (pci == NULL) { + pci = (struct proc_conf_info *)calloc(1, sizeof(struct proc_conf_info)); + if (pci == NULL) { + _E("Failed to allocate memory during parsing vendor configurations"); + return RESOURCED_ERROR_OUT_OF_MEMORY; + } + if (result->name[0] == 'A') { + pci->proc_type = APP_TYPE; + app_conf_info_list = g_slist_prepend(app_conf_info_list, (gpointer)pci); + } + else { + pci->proc_type = SERVICE_TYPE; + service_conf_info_list = g_slist_prepend(service_conf_info_list, (gpointer)pci); + } + pci->mem_type = CGROUP_TOP; + pci->cpu_type = CGROUP_TOP; + pci->cpu_priority = CPU_INIT_PRIO; + strncpy(pci->name, result->value, sizeof(pci->name)-1); + } + } + else if (!strncmp(result->name, CPU_CGROUP_NAME_CONF, strlen(CPU_CGROUP_NAME_CONF)+1) && + *config_type == LIMITER_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + + if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF, + strlen(CGROUP_VIP_VALUE_CONF) +1)) { + pci->cpu_type = CGROUP_VIP; + } + else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF, + strlen(CGROUP_HIGH_VALUE_CONF) +1)) { + pci->cpu_type = CGROUP_HIGH; + } + else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF, + strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) { + pci->cpu_type = CGROUP_MEDIUM; + } + else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF, + strlen(CGROUP_LOW_VALUE_CONF) +1)) { + pci->cpu_type = CGROUP_LOW; + } + else { + _E("invalid parameter (%s)", result->value); + return RESOURCED_ERROR_INVALID_PARAMETER; + } + } + else if (!strncmp(result->name, MEM_CGROUP_NAME_CONF, strlen(MEM_CGROUP_NAME_CONF)+1) && + *config_type == LIMITER_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + + if (!strncmp(result->value, CGROUP_VIP_VALUE_CONF, + strlen(CGROUP_VIP_VALUE_CONF) +1)) { + pci->mem_type = CGROUP_VIP; + } + else if (!strncmp(result->value, CGROUP_HIGH_VALUE_CONF, + strlen(CGROUP_HIGH_VALUE_CONF) +1)) { + pci->mem_type = CGROUP_HIGH; + } + else if (!strncmp(result->value, CGROUP_MEDIUM_VALUE_CONF, + strlen(CGROUP_MEDIUM_VALUE_CONF) +1)) { + pci->mem_type = CGROUP_MEDIUM; + } + else if (!strncmp(result->value, CGROUP_LOW_VALUE_CONF, + strlen(CGROUP_LOW_VALUE_CONF) +1)) { + pci->mem_type = CGROUP_LOW; + } + else { + _E("invalid parameter (%s)", result->value); + return RESOURCED_ERROR_INVALID_PARAMETER; + } + } + else if (!strncmp(result->name, MEM_LIMIT_ACTION_NAME_CONF, + strlen(MEM_LIMIT_ACTION_NAME_CONF)+1) && *config_type == LIMITER_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + + char *ptr = strchr(result->value, ','); + if (ptr == NULL) { + _E("Cannot find ',' in the string (%s)", result->value); + return RESOURCED_ERROR_FAIL; + } + + char *second_value = ptr + 1; + char temp; + + if (result->value > (ptr - 2)) { + _E("Size of string should be larger than 2"); + return RESOURCED_ERROR_FAIL; + } + + if (*(ptr - 1) == 'B') { + temp = *(ptr - 2); + *(ptr - 2) = '\0'; + + if (temp == 'G') { + pci->mem_action.memory = GBYTE_TO_MBYTE(atoi(result->value)); + } + else if (temp == 'M') { + pci->mem_action.memory = atoi(result->value); + } + else if (temp == 'K') { + pci->mem_action.memory = KBYTE_TO_MBYTE(atoi(result->value)); + } + else if (temp == ' ') { + pci->mem_action.memory = BYTE_TO_MBYTE(atoi(result->value)); + } + else { + _E("Memory size unit should be GB or MB or KB or B"); + return RESOURCED_ERROR_FAIL; + } + + if (!strncmp(second_value, ACTION_BROADCAST_VALUE_CONF, + strlen(ACTION_BROADCAST_VALUE_CONF)+1)) + pci->mem_action.action = PROC_ACTION_BROADCAST; + else if (!strncmp(second_value, ACTION_RECLAIM_VALUE_CONF, + strlen(ACTION_RECLAIM_VALUE_CONF)+1)) + pci->mem_action.action = PROC_ACTION_RECLAIM; + else if (!strncmp(second_value, ACTION_KILL_VALUE_CONF, + strlen(ACTION_KILL_VALUE_CONF)+1)) + pci->mem_action.action = PROC_ACTION_KILL; + else { + _E("action (%s) is not supported", second_value); + return RESOURCED_ERROR_FAIL; + } + } + else { + _E("Memory size unit should be XB"); + return RESOURCED_ERROR_FAIL; + } + } + else if (!strncmp(result->name, CPU_PRIORITY_NAME_CONF, strlen(CPU_PRIORITY_NAME_CONF)+1) && + *config_type == LIMITER_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + pci->cpu_priority = atoi(result->value); + } + else if (!strncmp(result->name, ACTION_ON_FAILURE_NAME_CONF, + strlen(ACTION_ON_FAILURE_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + + if (!strncmp(result->value, ACTION_REBOOT_VALUE_CONF, + strlen(ACTION_REBOOT_VALUE_CONF) +1)) { + pci->fail_action = PROC_ACTION_REBOOT; + } + else { + _E("invalid parameter (%s)", result->value); + return RESOURCED_ERROR_INVALID_PARAMETER; + } + } + else if (!strncmp(result->name, WATCHDOG_ACTION_NAME_CONF, + strlen(WATCHDOG_ACTION_NAME_CONF)+1) && *config_type == PROCESS_CONFIG) { + if (!pci) { + _E("process configuration information pointer should not be NULL"); + return RESOURCED_ERROR_FAIL; + } + + if (!strncmp(result->value, ACTION_IGNORE_VALUE_CONF, + strlen(ACTION_IGNORE_VALUE_CONF) +1)) { + pci->watchdog_action = PROC_ACTION_IGNORE; + } + else if (!strncmp(result->value, ACTION_KILL_VALUE_CONF, + strlen(ACTION_KILL_VALUE_CONF) +1)) { + pci->watchdog_action = PROC_ACTION_KILL; + } + else { + _E("invalid parameter (%s)", result->value); + return RESOURCED_ERROR_INVALID_PARAMETER; + } + } + else { + _E("Unknown configuration name (%s) and value (%s) on section (%s)", + result->name, result->value, result->section); + } + + return RESOURCED_ERROR_NONE; +} + +static void load_per_vendor_configs(const char *dir, int func(struct parse_result *result, + void *user_data), void *user_data) +{ + int count; + int idx; + struct dirent **namelist; + + if ((count = scandir(dir, &namelist, NULL, alphasort)) == -1) { + _W("failed to opendir (%s)", dir); + return; + } + + for (idx = 0; idx < count; idx++) { + char path[PATH_MAX] = {0, }; + + if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX)) + continue; + + snprintf(path, sizeof(path), "%s/%s", dir, namelist[idx]->d_name); + config_parse(path, func, user_data); + free(namelist[idx]); + } + + free(namelist); +} + +void resourced_parse_vendor_configs(void) +{ + int config_type; + + config_type = LIMITER_CONFIG; + load_per_vendor_configs(CGROUP_VIP_LIST_DIR, vendor_config, &config_type); + + config_type = PROCESS_CONFIG; + load_per_vendor_configs(PROC_CONF_DIR, vendor_config, &config_type); + + //DEBUG + GSList *iter; + gslist_for_each_item(iter, service_conf_info_list) { + struct proc_conf_info *pci = (struct proc_conf_info *)iter->data; + _I("[CONFIG] name: %s", pci->name); + _I("[CONFIG] mem cgroup: %d", pci->mem_type); + _I("[CONFIG] cpu cgroup: %d", pci->cpu_type); + _I("[CONFIG] cpu priority: %d", pci->cpu_priority); + _I("[CONFIG] watchdog_flag: %x", pci->watchdog_action); + _I("[CONFIG] fail_flag: %x", pci->fail_action); + _I("[CONFIG] memory: %lu MB", pci->mem_action.memory); + _I("[CONFIG] action: %d", pci->mem_action.action); + } + + gslist_for_each_item(iter, app_conf_info_list) { + struct proc_conf_info *pci = (struct proc_conf_info *)iter->data; + _I("[CONFIG] name: %s", pci->name); + _I("[CONFIG] mem cgroup: %d", pci->mem_type); + _I("[CONFIG] cpu cgroup: %d", pci->cpu_type); + _I("[CONFIG] cpu priority: %d", pci->cpu_priority); + _I("[CONFIG] watchdog_flag: %x", pci->watchdog_action); + _I("[CONFIG] fail_flag: %x", pci->fail_action); + _I("[CONFIG] memory: %lu MB", pci->mem_action.memory); + _I("[CONFIG] action: %d", pci->mem_action.action); + } +} int config_parse(const char *file_name, int cb(struct parse_result *result, void *user_data), void *user_data) diff --git a/src/common/config-parser.h b/src/common/config-parser.h index 09ad5ca..22deac1 100644 --- a/src/common/config-parser.h +++ b/src/common/config-parser.h @@ -27,11 +27,46 @@ extern "C" { #endif /* __cplusplus */ -#define PER_PROCESS_CONF "PerProcess" + +#define CONF_FILE_SUFFIX ".conf" + +#define CGROUP_VIP_LIST_DIR RD_CONFIG_PATH"/limiter.conf.d" +#define PROC_CONF_DIR "/etc/resourced/process.conf.d" + +#define PER_PROCESS_SECTION_CONF "PerProcess" + +/* configuration name */ +#define SERVICE_NAME_CONF "Service" +#define APP_NAME_CONF "App" +#define CPU_CGROUP_NAME_CONF "CpuGroup" +#define MEM_CGROUP_NAME_CONF "MemGroup" +#define MEM_LIMIT_ACTION_NAME_CONF "MemLimitAction" +#define CPU_PRIORITY_NAME_CONF "CpuPriority" +#define ACTION_ON_FAILURE_NAME_CONF "ActionOnFailure" +#define WATCHDOG_ACTION_NAME_CONF "WatchdogAction" + +/* configuration value */ +#define CGROUP_VIP_VALUE_CONF "vip" +#define CGROUP_HIGH_VALUE_CONF "high" +#define CGROUP_MEDIUM_VALUE_CONF "medium" +#define CGROUP_LOW_VALUE_CONF "lowest" +#define ACTION_BROADCAST_VALUE_CONF "broadcast" +#define ACTION_RECLAIM_VALUE_CONF "reclaim" +#define ACTION_KILL_VALUE_CONF "kill" +#define ACTION_REBOOT_VALUE_CONF "reboot" +#define ACTION_IGNORE_VALUE_CONF "ignore" + #define MATCH(a, b) (!strncmp(a, b, strlen(a) + 1) ? 1 : 0) #define SET_CONF(a, b) (a = (b > 0.0 ? b : a)) +enum config_type { + LIMITER_CONFIG, + OPTIMIZER_CONFIG, + MONITOR_CONFIG, + PROCESS_CONFIG, +}; + struct parse_result { char *section; char *name; @@ -86,6 +121,7 @@ int config_parse_float(const char *filename, unsigned line, const char *section, int config_parse_long(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data); int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data); +void resourced_parse_vendor_configs(void); #ifdef __cplusplus } #endif /* __cplusplus */ diff --git a/src/common/proc-common.h b/src/common/proc-common.h index 3c7951b..7630057 100644 --- a/src/common/proc-common.h +++ b/src/common/proc-common.h @@ -44,6 +44,37 @@ extern "C" { typedef GSList *pid_list; +enum proc_action { + PROC_ACTION_KILL = 0x1, + PROC_ACTION_RECLAIM = 0x2, + PROC_ACTION_BROADCAST = 0x4, + + PROC_ACTION_IGNORE = 0x8, + + PROC_ACTION_REBOOT = 0x16, +}; + +enum proc_type { + APP_TYPE, + SERVICE_TYPE, +}; + +struct mem_action { + unsigned long memory; /* MB */ + enum proc_action action; +}; + +struct proc_conf_info { + char name[PROC_NAME_MAX]; + enum proc_type proc_type; + enum cgroup_type mem_type; /* fixed memory cgroup */ + enum cgroup_type cpu_type; /* fixed cpu cgroup */ + int cpu_priority; /* fixed cpu priority */ + enum proc_action watchdog_action; /* watchdog action */ + enum proc_action fail_action; /* release action */ + struct mem_action mem_action; +}; + enum application_type { PROC_TYPE_NONE, PROC_TYPE_READY, diff --git a/src/common/util.h b/src/common/util.h index 3752ec1..affda26 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -88,6 +88,8 @@ static inline void closedirp(DIR **d) #define MBYTE_TO_BYTE(m) ((m) << 20) #define MBYTE_TO_KBYTE(m) ((m) << 10) +#define GBYTE_TO_MBYTE(g) ((g) << 10) + #define streq(a, b) (strncmp((a), (b), strlen(b)+1) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strcaseeq(a, b) (strcasecmp((a), (b)) == 0) diff --git a/src/process/watchdog/proc-watchdog.c b/src/process/watchdog/proc-watchdog.c index 06cb48d..6903f29 100644 --- a/src/process/watchdog/proc-watchdog.c +++ b/src/process/watchdog/proc-watchdog.c @@ -46,9 +46,6 @@ #include "module-data.h" #include "dbus-handler.h" -#define PROC_CONF_DIR "/etc/resourced/process.conf.d" -#define PROC_CONF_SUFFIX ".conf" - #define SYSTEMD_DBUS_DEST "org.freedesktop.systemd1" #define SYSTEMD_DBUS_UNIT_PATH "/org/freedesktop/systemd1/unit/" #define SYSTEMD_DBUS_SERVICE_IFACE SYSTEMD_DBUS_DEST".Service" @@ -258,7 +255,7 @@ static int proc_watchdog_load_config(struct parse_result *result, void *user_dat if (!user_data) return -1; - if (!strstr(result->section, PER_PROCESS_CONF)) + if (!strstr(result->section, PER_PROCESS_SECTION_CONF)) return -1; snprintf(vgname, sizeof(vgname), "%s:%s", (char *)user_data, result->section); @@ -420,7 +417,7 @@ static void proc_watchdog_load_configs(void) for (idx = 0; idx < count; idx++) { char path[PATH_MAX] = {0, }; - if (!strstr(namelist[idx]->d_name, PROC_CONF_SUFFIX)) + if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX)) continue; snprintf(path, sizeof(path), "%s/%s", PROC_CONF_DIR, namelist[idx]->d_name); diff --git a/src/resource-limiter/memory/vmpressure-lowmem-handler.c b/src/resource-limiter/memory/vmpressure-lowmem-handler.c index 36b46b0..f3f6d99 100644 --- a/src/resource-limiter/memory/vmpressure-lowmem-handler.c +++ b/src/resource-limiter/memory/vmpressure-lowmem-handler.c @@ -2287,7 +2287,7 @@ static void load_per_vendor_configs(void) for (idx = 0; idx < count; idx++) { char path[PATH_MAX] = {0, }; - if (!strstr(namelist[idx]->d_name, CGROUP_VIP_CONF_SUFFIX)) + if (!strstr(namelist[idx]->d_name, CONF_FILE_SUFFIX)) continue; snprintf(path, sizeof(path), "%s/%s", CGROUP_VIP_LIST_DIR, namelist[idx]->d_name); diff --git a/src/resourced/main.c b/src/resourced/main.c index 0a5a847..7a5dcbc 100644 --- a/src/resourced/main.c +++ b/src/resourced/main.c @@ -32,6 +32,7 @@ #include "proc-monitor.h" #include "trace.h" #include "notifier.h" +#include "config-parser.h" #include #include @@ -50,6 +51,13 @@ int main(int argc, char **argv) "Resourced initialization failed\n"); init_modules_arg(&darg); modules_check_runtime_support(NULL); + + /* parse vendor specific configuration files. + * resourced currently supports two dirs called limiter.conf.d and process.conf.d + * ex) /etc/resourced/xxx.d/yyy.conf + */ + resourced_parse_vendor_configs(); + if (resourced_restarted()) { _I("Relaunched. Start to initialize and restore"); modules_init(NULL); -- 2.7.4