]> www.infradead.org Git - users/hch/dma-mapping.git/commitdiff
selftests/mm: fix ARM related issue with fork after pthread_create
authorEdward Liaw <edliaw@google.com>
Mon, 25 Mar 2024 19:40:52 +0000 (19:40 +0000)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 26 Mar 2024 18:14:12 +0000 (11:14 -0700)
Following issue was observed while running the uffd-unit-tests selftest
on ARM devices. On x86_64 no issues were detected:

pthread_create followed by fork caused deadlock in certain cases wherein
fork required some work to be completed by the created thread.  Used
synchronization to ensure that created thread's start function has started
before invoking fork.

[edliaw@google.com: refactored to use atomic_bool]
Link: https://lkml.kernel.org/r/20240325194100.775052-1-edliaw@google.com
Fixes: 760aee0b71e3 ("selftests/mm: add tests for RO pinning vs fork()")
Signed-off-by: Lokesh Gidra <lokeshgidra@google.com>
Signed-off-by: Edward Liaw <edliaw@google.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/mm/uffd-common.c
tools/testing/selftests/mm/uffd-common.h
tools/testing/selftests/mm/uffd-unit-tests.c

index b0ac0ec2356d6533c55662949a0cd40ebe0a9c8d..7ad6ba660c7d6f1f5762d0b231b92b05e971a3c5 100644 (file)
@@ -18,6 +18,7 @@ bool test_uffdio_wp = true;
 unsigned long long *count_verify;
 uffd_test_ops_t *uffd_test_ops;
 uffd_test_case_ops_t *uffd_test_case_ops;
+atomic_bool ready_for_fork;
 
 static int uffd_mem_fd_create(off_t mem_size, bool hugetlb)
 {
@@ -518,6 +519,8 @@ void *uffd_poll_thread(void *arg)
        pollfd[1].fd = pipefd[cpu*2];
        pollfd[1].events = POLLIN;
 
+       ready_for_fork = true;
+
        for (;;) {
                ret = poll(pollfd, 2, -1);
                if (ret <= 0) {
index cb055282c89c966e93804478a2d47513939375a8..cc5629c3d2aa1057b9718ea5cbe3ef469b222877 100644 (file)
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 #include <stdint.h>
 #include <sys/random.h>
+#include <stdatomic.h>
 
 #include "../kselftest.h"
 #include "vm_util.h"
@@ -103,6 +104,7 @@ extern bool map_shared;
 extern bool test_uffdio_wp;
 extern unsigned long long *count_verify;
 extern volatile bool test_uffdio_copy_eexist;
+extern atomic_bool ready_for_fork;
 
 extern uffd_test_ops_t anon_uffd_test_ops;
 extern uffd_test_ops_t shmem_uffd_test_ops;
index 536e09b03aee0186cefc77d53536dffa9a4d5dbe..21ec23206ab44a0ed036cec25e2c79a461c83020 100644 (file)
@@ -775,6 +775,8 @@ static void uffd_sigbus_test_common(bool wp)
        char c;
        struct uffd_args args = { 0 };
 
+       ready_for_fork = false;
+
        fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK);
 
        if (uffd_register(uffd, area_dst, nr_pages * page_size,
@@ -790,6 +792,9 @@ static void uffd_sigbus_test_common(bool wp)
        if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args))
                err("uffd_poll_thread create");
 
+       while (!ready_for_fork)
+               ; /* Wait for the poll_thread to start executing before forking */
+
        pid = fork();
        if (pid < 0)
                err("fork");
@@ -829,6 +834,8 @@ static void uffd_events_test_common(bool wp)
        char c;
        struct uffd_args args = { 0 };
 
+       ready_for_fork = false;
+
        fcntl(uffd, F_SETFL, uffd_flags | O_NONBLOCK);
        if (uffd_register(uffd, area_dst, nr_pages * page_size,
                          true, wp, false))
@@ -838,6 +845,9 @@ static void uffd_events_test_common(bool wp)
        if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args))
                err("uffd_poll_thread create");
 
+       while (!ready_for_fork)
+               ; /* Wait for the poll_thread to start executing before forking */
+
        pid = fork();
        if (pid < 0)
                err("fork");