The test ignores the return value of fork(), so both the parent and
the (newly created) child run the COW verification loops and then
call hmm_buffer_free() before returning into the kselftest harness,
which _exit()s each side.  This duplicated teardown sequence has
been observed to manifest as a SIGSEGV in the test child, e.g.:

  hmm-tests[360141]: segfault (11) at 0 nip 10006964 lr 1000ac3c code 1
  in hmm-tests[6964,10000000+30000]

Fix this by adopting the same fork()-then-wait pattern already used
by the nearby anon_write_child / anon_write_child_shared tests in
this file: the child performs the COW verification and then _exit(0)s
so it does not run the test teardown, while the parent independently
verifies COW, waits for the child, and only then frees the buffer.

Fixes: b659baea75469 ("mm: selftests for exclusive device memory")
Signed-off-by: Aboorva Devarajan <[email protected]>
---
 tools/testing/selftests/mm/hmm-tests.c | 30 +++++++++++++++++++++++---
 1 file changed, 27 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/mm/hmm-tests.c 
b/tools/testing/selftests/mm/hmm-tests.c
index 1e5c1432ef6b..c5000d53b604 100644
--- a/tools/testing/selftests/mm/hmm-tests.c
+++ b/tools/testing/selftests/mm/hmm-tests.c
@@ -1866,6 +1866,8 @@ TEST_F(hmm, exclusive_cow)
        unsigned long i;
        int *ptr;
        int ret;
+       pid_t pid;
+       int status;
 
        npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
        ASSERT_NE(npages, 0);
@@ -1894,14 +1896,36 @@ TEST_F(hmm, exclusive_cow)
        ASSERT_EQ(ret, 0);
        ASSERT_EQ(buffer->cpages, npages);
 
-       fork();
+       pid = fork();
+       if (pid == -1)
+               ASSERT_EQ(pid, 0);
 
-       /* Fault pages back to system memory and check them. */
+       if (pid == 0) {
+               /*
+                * Child: fault pages back and verify COW, then _exit().
+                * On ASSERT failure the harness calls abort(); the parent
+                * reports it via the WIFEXITED/WEXITSTATUS checks below.
+                */
+               for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+                       ASSERT_EQ(ptr[i]++, i);
+
+               for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
+                       ASSERT_EQ(ptr[i], i + 1);
+
+               _exit(0);
+       }
+
+       /* Parent: also increment to verify COW works for both processes. */
        for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
                ASSERT_EQ(ptr[i]++, i);
 
        for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
-               ASSERT_EQ(ptr[i], i+1);
+               ASSERT_EQ(ptr[i], i + 1);
+
+       /* Parent: wait for child and then free the buffer. */
+       ASSERT_EQ(waitpid(pid, &status, 0), pid);
+       ASSERT_TRUE(WIFEXITED(status));
+       ASSERT_EQ(WEXITSTATUS(status), 0);
 
        hmm_buffer_free(buffer);
 }
-- 
2.54.0


Reply via email to