From 1d69d3d1e25bb03f1885c12f315232d047dddf64 Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Thu, 10 Feb 2022 18:22:59 +0800 Subject: [PATCH 1/7] Skip systemd managed processes jsc#PM-3309 --- src/main.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/main.c b/src/main.c index 60020f2..6e425e2 100644 --- a/src/main.c +++ b/src/main.c @@ -13,6 +13,7 @@ #define MAX_PIDS 16 #define CONF_FILE "/etc/sapwmp.conf" +#define LINE_LEN 1024 #define TASK_COMM_LEN 18 /* +2 for parentheses */ #define UNIT_NAME_LEN 128 @@ -39,6 +40,42 @@ static inline void freep(void *p) { free(*(void **)p); } +int _already_in_systemd(pid_t pid, const char *target_slice) { + char path[PATH_MAX]; + char buf[LINE_LEN]; + char pattern[UNIT_NAME_LEN + 2]; + FILE *f; + int r; + + r = snprintf(path, PATH_MAX, "/proc/%i/cgroup", pid); + if (r < 0) + return r; + + r = snprintf(pattern, UNIT_NAME_LEN + 2, "/%s/", target_slice); + if (r < 0) + return r; + + f = fopen(path, "r"); + if (!f) + return -errno; + + while (fgets(buf, LINE_LEN, f)) { + if (strncmp(buf, "0:", 2) != 0) + continue; + + if (strstr(buf, pattern)) { + log_info("Pid(%d) already in %s", pid, target_slice); + r = 1; + goto final; + } + } + r = 0; + +final: + fclose(f); + return r; +} + int migrate(sd_bus *bus, const char *target_unit, const char *target_slice, struct unit_config *properties, size_t n_pids, pid_t *pids) { @@ -106,6 +143,11 @@ int migrate(sd_bus *bus, const char *target_unit, const char *target_slice, return r; for (size_t i = 0; i < n_pids; i++) { + if (_already_in_systemd(pids[i], target_slice)) { + log_info("Skip pid(%d)", pids[i]); + continue; + } + r = sd_bus_message_append(m, "u", (uint32_t) pids[i]); if (r < 0) return r; @@ -290,6 +332,10 @@ int main(int argc, char *argv[]) { exit_error(EXIT_FAILURE, n_pids, "Failed collecting PIDs"); else if (n_pids == 0) exit_error(EXIT_SUCCESS, 0, "Empty capture"); + else if (n_pids == 1 && _already_in_systemd(pids[0], config.slice)) { + log_info("Do nothing"); + return EXIT_SUCCESS; + } r = make_scope_name(unit_name); if (r < 0) From 9e9e28eaded65bbe4aa756d927e91f3a8f3d19c3 Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Fri, 11 Feb 2022 11:28:21 +0800 Subject: [PATCH 2/7] Add switch f and avoid empty DBus message error. --- src/config.c | 1 - src/config.h | 1 + src/main.c | 30 +++++++++++++----------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/config.c b/src/config.c index 54e474a..0591c55 100644 --- a/src/config.c +++ b/src/config.c @@ -8,7 +8,6 @@ #define KILL_MODE_NONE "none" #define LIST_DELIM "," -#define LINE_LEN 1024 static void free_str_list(struct str_list *l) { free(l->list); diff --git a/src/config.h b/src/config.h index 9cd43d6..cb63eaf 100644 --- a/src/config.h +++ b/src/config.h @@ -2,6 +2,7 @@ #include #define CGROUP_LIMIT_MAX ((uint64_t) -1) +#define LINE_LEN 1024 /* List that was created as a split of a single string */ struct str_list { diff --git a/src/main.c b/src/main.c index 6e425e2..b509976 100644 --- a/src/main.c +++ b/src/main.c @@ -13,7 +13,6 @@ #define MAX_PIDS 16 #define CONF_FILE "/etc/sapwmp.conf" -#define LINE_LEN 1024 #define TASK_COMM_LEN 18 /* +2 for parentheses */ #define UNIT_NAME_LEN 128 @@ -64,7 +63,6 @@ int _already_in_systemd(pid_t pid, const char *target_slice) { continue; if (strstr(buf, pattern)) { - log_info("Pid(%d) already in %s", pid, target_slice); r = 1; goto final; } @@ -143,11 +141,6 @@ int migrate(sd_bus *bus, const char *target_unit, const char *target_slice, return r; for (size_t i = 0; i < n_pids; i++) { - if (_already_in_systemd(pids[i], target_slice)) { - log_info("Skip pid(%d)", pids[i]); - continue; - } - r = sd_bus_message_append(m, "u", (uint32_t) pids[i]); if (r < 0) return r; @@ -220,7 +213,7 @@ int read_stat(pid_t pid, pid_t *ppid, char *rcomm) { return r; } -int collect_pids(pid_t **rpids) { +int collect_pids(pid_t **rpids, int force) { int n_pids = 0; pid_t pid, ppid; char comm[TASK_COMM_LEN + 1]; @@ -244,7 +237,10 @@ int collect_pids(pid_t **rpids) { for (char **p = config.parent_commands.list; *p; p++) { if(!strcmp(comm, *p)) { - pids[n_pids++] = pid; + if (!force && _already_in_systemd(pid, config.slice)) + log_info("Found pid(%d) already in %s", pid, config.slice); + else + pids[n_pids++] = pid; break; } } @@ -279,11 +275,12 @@ static int make_scope_name(char *buf) { } static void print_help(const char *name) { - fprintf(stderr, "Usage: %s [-hv] -a\n", name); + fprintf(stderr, "Usage: %s [-hvf] -a\n", name); fprintf(stderr, " Similar to systemd-run --scope, logs into syslog unless stderr is a TTY\n"); fprintf(stderr, "\n"); fprintf(stderr, " -h Show this help\n"); fprintf(stderr, " -v Verbose logging (for debugging)\n"); + fprintf(stderr, " -f Force protect all valid processes(including systemd launched)\n"); fprintf(stderr, " -a Put chosen ancestor processes under WMP scope\n"); } @@ -291,13 +288,13 @@ int main(int argc, char *argv[]) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(freep) pid_t *pids = NULL; char unit_name[UNIT_NAME_LEN]; - int opt, ancestors = 0; + int opt, ancestors = 0, force = 0; int n_pids; int r; log_init(); - while ((opt = getopt(argc, argv, "ahv")) != -1) { + while ((opt = getopt(argc, argv, "ahvf")) != -1) { switch (opt) { case 'a': ancestors = 1; @@ -308,6 +305,9 @@ int main(int argc, char *argv[]) { case 'v': verbose = 1; break; + case 'f': + force = 1; + break; default: log_error("Unknown option(s), use -h for help"); } @@ -327,15 +327,11 @@ int main(int argc, char *argv[]) { if (r < 0) exit_error(EXIT_FAILURE, r, "Failed loading config from '%s'", CONF_FILE); - n_pids = collect_pids(&pids); + n_pids = collect_pids(&pids, force); if (n_pids < 0) exit_error(EXIT_FAILURE, n_pids, "Failed collecting PIDs"); else if (n_pids == 0) - exit_error(EXIT_SUCCESS, 0, "Empty capture"); - else if (n_pids == 1 && _already_in_systemd(pids[0], config.slice)) { - log_info("Do nothing"); return EXIT_SUCCESS; - } r = make_scope_name(unit_name); if (r < 0) From 19e4d9b16604a5b59f20f7639bbbaeaa4f9a631a Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Mon, 14 Feb 2022 12:18:55 +0800 Subject: [PATCH 3/7] check.sh: Fix a wmp check bug of memory_low_children --- scripts/wmp-check.sh | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/wmp-check.sh b/scripts/wmp-check.sh index 0b8f92f..7baadcb 100755 --- a/scripts/wmp-check.sh +++ b/scripts/wmp-check.sh @@ -283,20 +283,20 @@ function get_SAP_slice_data() { SAP_slice_data['memory.current']=${SAP_slice_data['memory.current']:=0} error=0 - while read path ; do - if [ -e "${path}/memory.low" ] ; then + while read path ; do + if [ ! -e "${path}/memory.low" ] ; then ((error++)) continue fi if [ "$(< ${path}/memory.low)" != 'max' ] ; then ((error++)) continue - fi + fi done < <(find "/sys/fs/cgroup/${SAP_slice_data['name']}/" -mindepth 1 -type d) - if [ ${error} -ne 0 ] ; then - SAP_slice_data['memory_low_children']='ok' - else + if [ ${error} -ne 0 ] ; then SAP_slice_data['memory_low_children']='false' + else + SAP_slice_data['memory_low_children']='ok' fi else SAP_slice_data['exists']='no' @@ -651,14 +651,14 @@ function check_wmp() { ((fails++)) ;; esac - case "${SAP_slice_data['memory_low_children']}" in + case "${SAP_slice_data['memory_low_children']}" in false) print_fail "Subcgroups of ${SAP_slice_data['name']} have either no MemoryLow setting or are not set to maximum!" "Check what has changed the parameters and restart the SAP instances." ((fails++)) ;; esac ;; - no) + no) print_fail "Unit file for ${SAP_slice_data['name']} is missing!" "Reinstall the sapwmp package." ((fails++)) ;; From 7a9e9d88120ed318b40742725b003d8f02ca8196 Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Mon, 14 Feb 2022 16:06:55 +0800 Subject: [PATCH 4/7] check.sh: Add unprotect_list check of subcgroups --- scripts/wmp-check.sh | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/scripts/wmp-check.sh b/scripts/wmp-check.sh index 7baadcb..8c639be 100755 --- a/scripts/wmp-check.sh +++ b/scripts/wmp-check.sh @@ -44,8 +44,9 @@ # 19.04.2021 v1.1.2 Remove sapstartsrv from process tree to capture # Enable support for SLE15SP3 # 1.11.2021 Enable support for SLE15SP4 +# 2.14.2022 v1.1.3 Adjust checker for SAP systemd integration -version="1.1.2" +version="1.1.3" # We use these global arrays through out the program: # @@ -281,23 +282,26 @@ function get_SAP_slice_data() { SAP_slice_data['memory.low']=${SAP_slice_data['memory.low']:=0} SAP_slice_data['memory.current']=$(cat "/sys/fs/cgroup/${SAP_slice_data['name']}/memory.current" 2>/dev/null) SAP_slice_data['memory.current']=${SAP_slice_data['memory.current']:=0} + SAP_slice_data['unprotect_list']=${SAP_slice_data['unprotect_list']:=''} error=0 while read path ; do - if [ ! -e "${path}/memory.low" ] ; then + if [ ! -e "${path}/memory.low" ] || [ "$(< ${path}/memory.low)" != 'max' ]; then + if [ ${#SAP_slice_data['unprotect_list']} -ne 0 ]; then + SAP_slice_data['unprotect_list']+=" ${path##*/}" + else + SAP_slice_data['unprotect_list']+="${path##*/}" + fi ((error++)) - continue - fi - if [ "$(< ${path}/memory.low)" != 'max' ] ; then - ((error++)) - continue fi done < <(find "/sys/fs/cgroup/${SAP_slice_data['name']}/" -mindepth 1 -type d) + if [ ${error} -ne 0 ] ; then SAP_slice_data['memory_low_children']='false' else SAP_slice_data['memory_low_children']='ok' fi + else SAP_slice_data['exists']='no' fi @@ -653,9 +657,18 @@ function check_wmp() { esac case "${SAP_slice_data['memory_low_children']}" in false) - print_fail "Subcgroups of ${SAP_slice_data['name']} have either no MemoryLow setting or are not set to maximum!" "Check what has changed the parameters and restart the SAP instances." - ((fails++)) - ;; + eval $(grep ^VERSION= /etc/os-release) + + case "${VERSION}" in + 15-SP4) + print_ok "In SLE15SP4, subcgroups of ${SAP_slice_data['name']} without MemoryLow setting is acceptable." + ;; + *) + print_fail "Subcgroups (${SAP_slice_data['unprotect_list']}) of ${SAP_slice_data['name']} have either no MemoryLow setting or are not set to maximum!" "Refer to the SUSE doc and check what has changed the parameters then restart the SAP instances." + ((fails++)) + ;; + esac + esac ;; no) From 9956af44149b0ee9279b17bd2809e2946e087fc5 Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Wed, 16 Feb 2022 10:36:04 +0800 Subject: [PATCH 5/7] Polish pull request based on review comments. 1. Move LINE_LEN back and use PATH_MAX 2. Rename _already_in_systemd to already_in_slice 3. Use break instead of goto in already_in_slice 4. Output "Empty capture" when no process captured --- src/config.c | 1 + src/config.h | 1 - src/main.c | 39 +++++++++++++++++++++++++-------------- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/src/config.c b/src/config.c index 0591c55..54e474a 100644 --- a/src/config.c +++ b/src/config.c @@ -8,6 +8,7 @@ #define KILL_MODE_NONE "none" #define LIST_DELIM "," +#define LINE_LEN 1024 static void free_str_list(struct str_list *l) { free(l->list); diff --git a/src/config.h b/src/config.h index cb63eaf..9cd43d6 100644 --- a/src/config.h +++ b/src/config.h @@ -2,7 +2,6 @@ #include #define CGROUP_LIMIT_MAX ((uint64_t) -1) -#define LINE_LEN 1024 /* List that was created as a split of a single string */ struct str_list { diff --git a/src/main.c b/src/main.c index b509976..12ab64b 100644 --- a/src/main.c +++ b/src/main.c @@ -39,9 +39,9 @@ static inline void freep(void *p) { free(*(void **)p); } -int _already_in_systemd(pid_t pid, const char *target_slice) { +int already_in_slice(pid_t pid, const char *target_slice) { char path[PATH_MAX]; - char buf[LINE_LEN]; + char buf[PATH_MAX]; char pattern[UNIT_NAME_LEN + 2]; FILE *f; int r; @@ -58,18 +58,17 @@ int _already_in_systemd(pid_t pid, const char *target_slice) { if (!f) return -errno; - while (fgets(buf, LINE_LEN, f)) { + r = 0; + while (fgets(buf, PATH_MAX, f)) { if (strncmp(buf, "0:", 2) != 0) continue; if (strstr(buf, pattern)) { r = 1; - goto final; + break; } } - r = 0; -final: fclose(f); return r; } @@ -215,6 +214,7 @@ int read_stat(pid_t pid, pid_t *ppid, char *rcomm) { int collect_pids(pid_t **rpids, int force) { int n_pids = 0; + int r; pid_t pid, ppid; char comm[TASK_COMM_LEN + 1]; pid_t *pids; @@ -230,17 +230,28 @@ int collect_pids(pid_t **rpids, int force) { pid = getppid(); while (pid > 1 && n_pids < MAX_PIDS) { - if (read_stat(pid, &ppid, comm)) + if (read_stat(pid, &ppid, comm)) { + r = -ESRCH; goto err; + } + if (verbose) log_debug("%10i: %s", pid, comm); for (char **p = config.parent_commands.list; *p; p++) { if(!strcmp(comm, *p)) { - if (!force && _already_in_systemd(pid, config.slice)) - log_info("Found pid(%d) already in %s", pid, config.slice); - else - pids[n_pids++] = pid; + if (!force) { + r = already_in_slice(pid, config.slice); + + if (r < 0) + goto err; + else if (r == 1) { + log_info("Found pid(%d) already in %s", pid, config.slice); + break; + } + } + + pids[n_pids++] = pid; break; } } @@ -254,7 +265,7 @@ int collect_pids(pid_t **rpids, int force) { err: free(pids); - return -ESRCH; + return r; } static int make_scope_name(char *buf) { @@ -280,7 +291,7 @@ static void print_help(const char *name) { fprintf(stderr, "\n"); fprintf(stderr, " -h Show this help\n"); fprintf(stderr, " -v Verbose logging (for debugging)\n"); - fprintf(stderr, " -f Force protect all valid processes(including systemd launched)\n"); + fprintf(stderr, " -f Force capture all valid processes(including systemd launched)\n"); fprintf(stderr, " -a Put chosen ancestor processes under WMP scope\n"); } @@ -331,7 +342,7 @@ int main(int argc, char *argv[]) { if (n_pids < 0) exit_error(EXIT_FAILURE, n_pids, "Failed collecting PIDs"); else if (n_pids == 0) - return EXIT_SUCCESS; + exit_error(EXIT_SUCCESS, 0, "Empty capture"); r = make_scope_name(unit_name); if (r < 0) From 439413158134b3921c609e7dee8029174ce4476d Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Fri, 18 Feb 2022 11:18:44 +0800 Subject: [PATCH 6/7] wmp-check: raise error when user not configure MemoryLow of target slice in digital. --- scripts/wmp-check.sh | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/scripts/wmp-check.sh b/scripts/wmp-check.sh index 8c639be..7b56c33 100755 --- a/scripts/wmp-check.sh +++ b/scripts/wmp-check.sh @@ -698,21 +698,26 @@ function check_wmp() { # Check if MemoryLow of the SAP slice is lower the memory.current and less then 3% as physical memory. if [ -n "${SAP_slice_data['MemoryLow']}" ] ; then - if [ ${SAP_slice_data['MemoryLow']} -gt ${SAP_slice_data['memory.current']} ] ; then - print_ok "MemoryLow is larger then the current allocated memory for ${SAP_slice_data['name']}." - else - print_fail "MemoryLow (${SAP_slice_data['MemoryLow']}) is smaller then the current allocated memory (${SAP_slice_data['memory.current']}) for ${SAP_slice_data['name']}!" "Check if this is an expected situation." - ((fails++)) - fi - if [ ${SAP_slice_data['MemoryLow']} -lt ${memory_info['MemTotal']} ] ; then - print_ok "MemoryLow of ${SAP_slice_data['name']} is less then total memory." - memory_low_thresh=$(( ${memory_info['MemTotal']} * 97 / 100 )) - if [ ${SAP_slice_data['MemoryLow']} -gt ${memory_low_thresh} ] ; then - print_warn "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is very close to the total physical memory (${memory_info['MemTotal']})!" - ((warnings++)) + if grep -q '^[[:digit:]]*$' <<< "${SAP_slice_data['MemoryLow']}";then + if [ ${SAP_slice_data['MemoryLow']} -gt ${SAP_slice_data['memory.current']} ] ; then + print_ok "MemoryLow is larger then the current allocated memory for ${SAP_slice_data['name']}." + else + print_fail "MemoryLow (${SAP_slice_data['MemoryLow']}) is smaller then the current allocated memory (${SAP_slice_data['memory.current']}) for ${SAP_slice_data['name']}!" "Check if this is an expected situation." + ((fails++)) + fi + if [ ${SAP_slice_data['MemoryLow']} -lt ${memory_info['MemTotal']} ] ; then + print_ok "MemoryLow of ${SAP_slice_data['name']} is less then total memory." + memory_low_thresh=$(( ${memory_info['MemTotal']} * 97 / 100 )) + if [ ${SAP_slice_data['MemoryLow']} -gt ${memory_low_thresh} ] ; then + print_warn "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is very close to the total physical memory (${memory_info['MemTotal']})!" + ((warnings++)) + fi + else + print_fail "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is not less then the total physical memory (${memory_info['MemTotal']})!" "Reduce MemoryLow." + ((fails++)) fi else - print_fail "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is not less then the total physical memory (${memory_info['MemTotal']})!" "Reduce MemoryLow." + print_fail "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is not digital!" "Configure MemoryLow to a number." ((fails++)) fi else From 9466dcff97899d252bd369955a8ce15963f88237 Mon Sep 17 00:00:00 2001 From: Nick Wang Date: Fri, 18 Feb 2022 23:09:36 +0800 Subject: [PATCH 7/7] wmp-check: Polish the phrase of error output. --- scripts/wmp-check.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/wmp-check.sh b/scripts/wmp-check.sh index 7b56c33..e5e4288 100755 --- a/scripts/wmp-check.sh +++ b/scripts/wmp-check.sh @@ -717,7 +717,7 @@ function check_wmp() { ((fails++)) fi else - print_fail "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is not digital!" "Configure MemoryLow to a number." + print_fail "MemoryLow of ${SAP_slice_data['name']} (${SAP_slice_data['MemoryLow']}) is not a numeric value!" "Configure MemoryLow to a number." ((fails++)) fi else