On Sun, Aug 07, 2022 at 12:49:16AM +0200, Carsten Emde wrote: > If the PF_NO_SETAFFINITY process flag is set, the user may not > know why the affinity is not settable. Write a respective message > and do not attempt to set the affinity of this process. I'm unsure if constantly checking for the flag rather than calling sched_setaffinity() is the right way. It seems pretty expensive. I don't like when userspace tries to predict any kernel policy or behavior. It seems better to call the syscall and, if necessary, compose a better (detailed) error message. What about the patch below? (I have moved /proc/#/stat parsing to lib/procfs.c to keep tastset.c more readable.) Karel diff --git a/include/procfs.h b/include/procfs.h index 5a730c94c..825689bc2 100644 --- a/include/procfs.h +++ b/include/procfs.h @@ -30,6 +30,7 @@ extern ssize_t procfs_process_get_cmdline(struct path_cxt *pc, char *buf, size_t extern ssize_t procfs_process_get_cmdname(struct path_cxt *pc, char *buf, size_t bufsz); extern ssize_t procfs_process_get_stat(struct path_cxt *pc, char *buf, size_t bufsz); +extern int procfs_process_get_stat_nth(struct path_cxt *pc, int n, uintmax_t *re); static inline ssize_t procfs_process_get_exe(struct path_cxt *pc, char *buf, size_t bufsz) { diff --git a/lib/procfs.c b/lib/procfs.c index 0d58857c8..1072a9a2c 100644 --- a/lib/procfs.c +++ b/lib/procfs.c @@ -169,6 +169,35 @@ ssize_t procfs_process_get_stat(struct path_cxt *pc, char *buf, size_t bufsz) return procfs_process_get_line_for(pc, buf, bufsz, "stat"); } +int procfs_process_get_stat_nth(struct path_cxt *pc, int n, uintmax_t *re) +{ + ssize_t rc; + char *key = NULL, *tok, *p; + char buf[BUFSIZ]; + int i; + + if (n == 2 || n == 3) /* process name and status (strings) */ + return -EINVAL; + + rc = procfs_process_get_line_for(pc, buf, sizeof(buf), "stat"); + if (rc < 0) + return rc; + + for (i = 0, tok = strtok_r(buf, " ", &key); tok; + tok = strtok_r(NULL, " ", &key)) { + + i++; + if (i == n) + return ul_strtou64(tok, re, 10); + + /* skip rest of the process name */ + if (i == 2 && (p = strchr(key, ')'))) + key = p + 2; + } + + return -EINVAL; +} + int procfs_process_get_uid(struct path_cxt *pc, uid_t *uid) { struct stat sb; @@ -547,6 +576,30 @@ static int test_isprocfs(int argc, char *argv[]) return is ? EXIT_SUCCESS : EXIT_FAILURE; } +static int test_process_stat_nth(int argc, char *argv[]) +{ + pid_t pid; + struct path_cxt *pc; + uintmax_t num = 0; + int n; + + if (argc != 3) + return EXIT_FAILURE; + pid = strtol(argv[1], (char **) NULL, 10); + n = strtol(argv[2], (char **) NULL, 10); + + pc = ul_new_procfs_path(pid, NULL); + if (!pc) + err(EXIT_FAILURE, "cannot alloc procfs handler"); + + if (procfs_process_get_stat_nth(pc, n, &num) != 0) + err(EXIT_FAILURE, "read %dth number failed", n); + + printf("%d: %dth %ju\n", (int) pid, n, num); + ul_unref_path(pc); + return EXIT_SUCCESS; +} + int main(int argc, char *argv[]) { if (argc < 2) { @@ -554,7 +607,8 @@ int main(int argc, char *argv[]) " %1$s --fds <pid>\n" " %1$s --is-procfs [<dir>]\n" " %1$s --processes [---name <name>] [--uid <uid>]\n" - " %1$s --one <pid>\n", + " %1$s --one <pid>\n" + " %1$s --stat-nth <pid> <n>\n", program_invocation_short_name); return EXIT_FAILURE; } @@ -569,6 +623,8 @@ int main(int argc, char *argv[]) return test_isprocfs(argc - 1, argv + 1); if (strcmp(argv[1], "--one") == 0) return test_one_process(argc - 1, argv + 1); + if (strcmp(argv[1], "--stat-nth") == 0) + return test_process_stat_nth(argc - 1, argv + 1); return EXIT_FAILURE; } diff --git a/schedutils/taskset.c b/schedutils/taskset.c index 0ab7d12e2..d2d1a869e 100644 --- a/schedutils/taskset.c +++ b/schedutils/taskset.c @@ -112,6 +112,8 @@ static void __attribute__((__noreturn__)) err_affinity(pid_t pid, int set) err(EXIT_FAILURE, msg, pid ? pid : getpid()); } +#define PF_NO_SETAFFINITY 0x04000000 + static void do_taskset(struct taskset *ts, size_t setsize, cpu_set_t *set) { /* read the current mask */ @@ -125,8 +127,22 @@ static void do_taskset(struct taskset *ts, size_t setsize, cpu_set_t *set) return; /* set new mask */ - if (sched_setaffinity(ts->pid, setsize, set) < 0) + if (sched_setaffinity(ts->pid, setsize, set) < 0) { + uintmax_t flags = 0; + struct path_cxt *pc; + int errsv = errno; + + if (errno != EPERM + && (pc = ul_new_procfs_path(ts->pid, NULL)) + && procfs_process_get_stat_nth(pc, 9, &flags) == 0 + && (flags & PF_NO_SETAFFINITY)) { + warnx(_("affinity cannot be set due to PF_NO_SETAFFINITY flag set")); + errno = EINVAL; + } else + errno = errsv; + err_affinity(ts->pid, 1); + } /* re-read the current mask */ if (ts->pid) { -- Karel Zak <kzak@xxxxxxxxxx> http://karelzak.blogspot.com