Merge tag 'linux_kselftest-next-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / tools / testing / selftests / resctrl / resctrl_val.c
index f0f6c5f6e98b9b4ccd66f03e1e86df7ce2b0f8a5..88789678917b6b9d799bd7ee54f4e9c9ecf7d311 100644 (file)
@@ -468,7 +468,9 @@ pid_t bm_pid, ppid;
 
 void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
 {
-       kill(bm_pid, SIGKILL);
+       /* Only kill child after bm_pid is set after fork() */
+       if (bm_pid)
+               kill(bm_pid, SIGKILL);
        umount_resctrlfs();
        tests_cleanup();
        ksft_print_msg("Ending\n\n");
@@ -482,9 +484,11 @@ void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
  */
 int signal_handler_register(void)
 {
-       struct sigaction sigact;
+       struct sigaction sigact = {};
        int ret = 0;
 
+       bm_pid = 0;
+
        sigact.sa_sigaction = ctrlc_handler;
        sigemptyset(&sigact.sa_mask);
        sigact.sa_flags = SA_SIGINFO;
@@ -504,7 +508,7 @@ int signal_handler_register(void)
  */
 void signal_handler_unregister(void)
 {
-       struct sigaction sigact;
+       struct sigaction sigact = {};
 
        sigact.sa_handler = SIG_DFL;
        sigemptyset(&sigact.sa_mask);
@@ -621,6 +625,56 @@ measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
        return 0;
 }
 
+/*
+ * run_benchmark - Run a specified benchmark or fill_buf (default benchmark)
+ *                in specified signal. Direct benchmark stdio to /dev/null.
+ * @signum:    signal number
+ * @info:      signal info
+ * @ucontext:  user context in signal handling
+ */
+static void run_benchmark(int signum, siginfo_t *info, void *ucontext)
+{
+       int operation, ret, memflush;
+       char **benchmark_cmd;
+       size_t span;
+       bool once;
+       FILE *fp;
+
+       benchmark_cmd = info->si_ptr;
+
+       /*
+        * Direct stdio of child to /dev/null, so that only parent writes to
+        * stdio (console)
+        */
+       fp = freopen("/dev/null", "w", stdout);
+       if (!fp)
+               PARENT_EXIT("Unable to direct benchmark status to /dev/null");
+
+       if (strcmp(benchmark_cmd[0], "fill_buf") == 0) {
+               /* Execute default fill_buf benchmark */
+               span = strtoul(benchmark_cmd[1], NULL, 10);
+               memflush =  atoi(benchmark_cmd[2]);
+               operation = atoi(benchmark_cmd[3]);
+               if (!strcmp(benchmark_cmd[4], "true"))
+                       once = true;
+               else if (!strcmp(benchmark_cmd[4], "false"))
+                       once = false;
+               else
+                       PARENT_EXIT("Invalid once parameter");
+
+               if (run_fill_buf(span, memflush, operation, once))
+                       fprintf(stderr, "Error in running fill buffer\n");
+       } else {
+               /* Execute specified benchmark */
+               ret = execvp(benchmark_cmd[0], benchmark_cmd);
+               if (ret)
+                       perror("wrong\n");
+       }
+
+       fclose(stdout);
+       PARENT_EXIT("Unable to run specified benchmark");
+}
+
 /*
  * resctrl_val:        execute benchmark and measure memory bandwidth on
  *                     the benchmark
@@ -629,7 +683,7 @@ measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
  *
  * Return:             0 on success. non-zero on failure.
  */
-int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
+int resctrl_val(const char * const *benchmark_cmd, struct resctrl_val_param *param)
 {
        char *resctrl_val = param->resctrl_val;
        unsigned long bw_resc_start = 0;
@@ -706,28 +760,30 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
 
        ksft_print_msg("Benchmark PID: %d\n", bm_pid);
 
-       ret = signal_handler_register();
-       if (ret)
-               goto out;
-
-       value.sival_ptr = benchmark_cmd;
+       /*
+        * The cast removes constness but nothing mutates benchmark_cmd within
+        * the context of this process. At the receiving process, it becomes
+        * argv, which is mutable, on exec() but that's after fork() so it
+        * doesn't matter for the process running the tests.
+        */
+       value.sival_ptr = (void *)benchmark_cmd;
 
        /* Taskset benchmark to specified cpu */
        ret = taskset_benchmark(bm_pid, param->cpu_no);
        if (ret)
-               goto unregister;
+               goto out;
 
        /* Write benchmark to specified control&monitoring grp in resctrl FS */
        ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
                                      resctrl_val);
        if (ret)
-               goto unregister;
+               goto out;
 
        if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
            !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
                ret = initialize_mem_bw_imc();
                if (ret)
-                       goto unregister;
+                       goto out;
 
                initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
                                          param->cpu_no, resctrl_val);
@@ -742,7 +798,7 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
                    sizeof(pipe_message)) {
                        perror("# failed reading message from child process");
                        close(pipefd[0]);
-                       goto unregister;
+                       goto out;
                }
        }
        close(pipefd[0]);
@@ -751,7 +807,7 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
        if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
                perror("# sigqueue SIGUSR1 to child");
                ret = errno;
-               goto unregister;
+               goto out;
        }
 
        /* Give benchmark enough time to fully run */
@@ -780,8 +836,6 @@ int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
                }
        }
 
-unregister:
-       signal_handler_unregister();
 out:
        kill(bm_pid, SIGKILL);