]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/mm: fix exclusive_cow test fork() handling
authorAboorva Devarajan <aboorvad@linux.ibm.com>
Thu, 11 Jun 2026 03:41:02 +0000 (09:11 +0530)
committerAndrew Morton <akpm@linux-foundation.org>
Sun, 21 Jun 2026 18:37:38 +0000 (11:37 -0700)
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.

Link: https://lore.kernel.org/20260611034102.1030738-4-aboorvad@linux.ibm.com
Fixes: b659baea75469 ("mm: selftests for exclusive device memory")
Signed-off-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
Cc: Alex Sierra <alex.sierra@amd.com>
Cc: Alistair Popple <apopple@nvidia.com>
Cc: Balbir Singh <balbirs@nvidia.com>
Cc: David Hildenbrand <david@kernel.org>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Mike Rapoport <rppt@kernel.org>
Cc: Ralph Campbell <rcampbell@nvidia.com>
Cc: Sayali Patil <sayalip@linux.ibm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/mm/hmm-tests.c

index 8f4f824670436c4d807920b1b91f751bbafa9f8a..e4c49699f3f728aadaa935be6df2fc0d9fc482ac 100644 (file)
@@ -1884,6 +1884,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);
@@ -1912,14 +1914,37 @@ 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 verifies COW independently, then _exit(0)s so it does
+                * not run the test teardown.  A failed ASSERT_* here makes the
+                * harness abort() the child, so the parent sees
+                * !WIFEXITED(status) below and fails in turn.
+                */
+               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);
 }