selftests/x86/lam: Add test cases for LAM vs thread creation
authorKirill A. Shutemov <kirill.shutemov@linux.intel.com>
Sun, 12 Mar 2023 11:26:12 +0000 (14:26 +0300)
committerDave Hansen <dave.hansen@linux.intel.com>
Thu, 16 Mar 2023 20:08:41 +0000 (13:08 -0700)
LAM enabling is only allowed when the process has single thread.
LAM mode is inherited into child thread.

Trying to enable LAM after spawning a thread has to fail.

Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20230312112612.31869-18-kirill.shutemov%40linux.intel.com
tools/testing/selftests/x86/lam.c

index a8c9182..eb0e469 100644 (file)
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -12,6 +13,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 #include <inttypes.h>
+#include <sched.h>
 
 #include <sys/uio.h>
 #include <linux/io_uring.h>
@@ -50,6 +52,8 @@
 
 #define PAGE_SIZE               (4 << 10)
 
+#define STACK_SIZE             65536
+
 #define barrier() ({                                           \
                   __asm__ __volatile__("" : : : "memory");     \
 })
@@ -731,6 +735,75 @@ static int handle_inheritance(struct testcases *test)
        return 0;
 }
 
+static int thread_fn_get_lam(void *arg)
+{
+       return get_lam();
+}
+
+static int thread_fn_set_lam(void *arg)
+{
+       struct testcases *test = arg;
+
+       return set_lam(test->lam);
+}
+
+static int handle_thread(struct testcases *test)
+{
+       char stack[STACK_SIZE];
+       int ret, child_ret;
+       int lam = 0;
+       pid_t pid;
+
+       /* Set LAM mode in parent process */
+       if (!test->later) {
+               lam = test->lam;
+               if (set_lam(lam) != 0)
+                       return 1;
+       }
+
+       pid = clone(thread_fn_get_lam, stack + STACK_SIZE,
+                   SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, NULL);
+       if (pid < 0) {
+               perror("Clone failed.");
+               return 1;
+       }
+
+       waitpid(pid, &child_ret, 0);
+       ret = WEXITSTATUS(child_ret);
+
+       if (lam != ret)
+               return 1;
+
+       if (test->later) {
+               if (set_lam(test->lam) != 0)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static int handle_thread_enable(struct testcases *test)
+{
+       char stack[STACK_SIZE];
+       int ret, child_ret;
+       int lam = test->lam;
+       pid_t pid;
+
+       pid = clone(thread_fn_set_lam, stack + STACK_SIZE,
+                   SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, test);
+       if (pid < 0) {
+               perror("Clone failed.");
+               return 1;
+       }
+
+       waitpid(pid, &child_ret, 0);
+       ret = WEXITSTATUS(child_ret);
+
+       if (lam != ret)
+               return 1;
+
+       return 0;
+}
 static void run_test(struct testcases *test, int count)
 {
        int i, ret = 0;
@@ -849,6 +922,25 @@ static struct testcases inheritance_cases[] = {
        {
                .expected = 0,
                .lam = LAM_U57_BITS,
+               .test_func = handle_thread,
+               .msg = "THREAD: LAM_U57, child thread should get LAM mode same as parent\n",
+       },
+       {
+               .expected = 1,
+               .lam = LAM_U57_BITS,
+               .test_func = handle_thread_enable,
+               .msg = "THREAD: [NEGATIVE] Enable LAM in child.\n",
+       },
+       {
+               .expected = 1,
+               .later = 1,
+               .lam = LAM_U57_BITS,
+               .test_func = handle_thread,
+               .msg = "THREAD: [NEGATIVE] Enable LAM in parent after thread created.\n",
+       },
+       {
+               .expected = 0,
+               .lam = LAM_U57_BITS,
                .test_func = handle_execve,
                .msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n",
        },