pthread_join() returns once exit_mm() wakes the CLEARTID futex, but the
exiting thread drops its namespace reference later, in
exit_nsproxy_namespaces(). The joining thread can therefore still see the
namespace as active, making the final open_by_handle_at() check in
thread_ns_inactive_after_exit and thread_ns_fd_keeps_active fail
intermittently.

Have the thread open a PIDFD_THREAD pidfd on itself and poll it before
pthread_join(). A pidfd becomes readable from exit_notify(), which runs
after exit_nsproxy_namespaces().

Fixes: 29f083c49982 ("selftests/namespace: first threaded active reference 
count test")
Fixes: ee861032381b ("selftests/namespace: second threaded active reference 
count test")
Assisted-by: LLM
Signed-off-by: Ricardo B. Marlière (SUSE) <[email protected]>
---
 .../selftests/namespaces/ns_active_ref_test.c      | 29 ++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/tools/testing/selftests/namespaces/ns_active_ref_test.c 
b/tools/testing/selftests/namespaces/ns_active_ref_test.c
index 093268f0efaa..ab5ffe4de521 100644
--- a/tools/testing/selftests/namespaces/ns_active_ref_test.c
+++ b/tools/testing/selftests/namespaces/ns_active_ref_test.c
@@ -8,6 +8,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <linux/nsfs.h>
+#include <poll.h>
 #include <sys/mount.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
@@ -20,6 +21,10 @@
 #include "../filesystems/utils.h"
 #include "wrappers.h"
 
+#ifndef PIDFD_THREAD
+#define PIDFD_THREAD O_EXCL
+#endif
+
 #ifndef FD_NSFS_ROOT
 #define FD_NSFS_ROOT -10003 /* Root of the nsfs filesystem */
 #endif
@@ -2120,6 +2125,7 @@ TEST(ns_mixed_types_same_owner)
 /* Thread test helpers and structures */
 struct thread_ns_info {
        __u64 ns_id;
+       int pidfd;
        int pipefd;
        int syncfd_read;
        int syncfd_write;
@@ -2152,6 +2158,13 @@ static void *thread_create_namespace(void *arg)
                return NULL;
        }
 
+       /* Open a pidfd so the main thread can later poll it to detect actual 
thread exit. */
+       info->pidfd = syscall(__NR_pidfd_open, gettid(), PIDFD_THREAD);
+       if (info->pidfd < 0) {
+               info->exit_code = 6;
+               return NULL;
+       }
+
        /* Send namespace ID to main thread */
        if (write(info->pipefd, &info->ns_id, sizeof(info->ns_id)) != 
sizeof(info->ns_id)) {
                info->exit_code = 4;
@@ -2169,6 +2182,20 @@ static void *thread_create_namespace(void *arg)
        return NULL;
 }
 
+/*
+ * pthread_join() returns once exit_mm() wakes the CLEARTID futex, before
+ * exit_nsproxy_namespaces() drops the namespace reference. A pidfd becomes
+ * readable only from exit_notify(), after that point.
+ */
+static int wait_thread_exited(int pidfd)
+{
+       struct pollfd pfd = { .fd = pidfd, .events = POLLIN };
+       int ret = poll(&pfd, 1, -1);
+
+       close(pidfd);
+       return ret;
+}
+
 /*
  * Test that namespace becomes inactive after thread exits.
  * This verifies active reference counting works with threads, not just 
processes.
@@ -2234,6 +2261,7 @@ TEST(thread_ns_inactive_after_exit)
        close(syncpipe[1]);
 
        /* Wait for thread to exit */
+       ASSERT_EQ(wait_thread_exited(info.pidfd), 1);
        ASSERT_EQ(pthread_join(thread, NULL), 0);
        close(pipefd[0]);
        close(pipefd[1]);
@@ -2317,6 +2345,7 @@ TEST(thread_ns_fd_keeps_active)
        close(syncpipe[1]);
 
        /* Wait for thread to exit */
+       ASSERT_EQ(wait_thread_exited(info.pidfd), 1);
        pthread_join(thread, NULL);
        close(pipefd[0]);
        close(pipefd[1]);

---
base-commit: 551c722f40809618230001baccf219193e22fc5a
change-id: 20261001-selftests-namespaces-nsid_race-d65dac740e6b

Best regards,
--  
Ricardo B. Marlière (SUSE) <[email protected]>


Reply via email to