]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
selftests/namespaces: second active reference count tests
authorChristian Brauner <brauner@kernel.org>
Wed, 29 Oct 2025 12:20:37 +0000 (13:20 +0100)
committerChristian Brauner <brauner@kernel.org>
Mon, 3 Nov 2025 16:41:19 +0000 (17:41 +0100)
Test namespace lifecycle: create a namespace in a child process, get a
file handle while it's active, then try to reopen after the process
exits (namespace becomes inactive).

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-24-2e6f823ebdc0@kernel.org
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Christian Brauner <brauner@kernel.org>
tools/testing/selftests/namespaces/ns_active_ref_test.c

index 21514a537b26541244a473803cba932f393e72ca..7cade298c754ddc522eb76ec4da1c16273f5888c 100644 (file)
@@ -71,4 +71,85 @@ TEST(init_ns_always_active)
        free(handle);
 }
 
+/*
+ * Test namespace lifecycle: create a namespace in a child process,
+ * get a file handle while it's active, then try to reopen after
+ * the process exits (namespace becomes inactive).
+ */
+TEST(ns_inactive_after_exit)
+{
+       struct file_handle *handle;
+       int mount_id;
+       int ret;
+       int fd;
+       int pipefd[2];
+       pid_t pid;
+       int status;
+       char buf[sizeof(*handle) + MAX_HANDLE_SZ];
+
+       /* Create pipe for passing file handle from child */
+       ASSERT_EQ(pipe(pipefd), 0);
+
+       pid = fork();
+       ASSERT_GE(pid, 0);
+
+       if (pid == 0) {
+               /* Child process */
+               close(pipefd[0]);
+
+               /* Create new network namespace */
+               ret = unshare(CLONE_NEWNET);
+               if (ret < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               /* Open our new namespace */
+               fd = open("/proc/self/ns/net", O_RDONLY);
+               if (fd < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               /* Get file handle for the namespace */
+               handle = (struct file_handle *)buf;
+               handle->handle_bytes = MAX_HANDLE_SZ;
+               ret = name_to_handle_at(fd, "", handle, &mount_id, AT_EMPTY_PATH);
+               close(fd);
+
+               if (ret < 0) {
+                       close(pipefd[1]);
+                       exit(1);
+               }
+
+               /* Send handle to parent */
+               write(pipefd[1], buf, sizeof(*handle) + handle->handle_bytes);
+               close(pipefd[1]);
+
+               /* Exit - namespace should become inactive */
+               exit(0);
+       }
+
+       /* Parent process */
+       close(pipefd[1]);
+
+       /* Read file handle from child */
+       ret = read(pipefd[0], buf, sizeof(buf));
+       close(pipefd[0]);
+
+       /* Wait for child to exit */
+       waitpid(pid, &status, 0);
+       ASSERT_TRUE(WIFEXITED(status));
+       ASSERT_EQ(WEXITSTATUS(status), 0);
+
+       ASSERT_GT(ret, 0);
+       handle = (struct file_handle *)buf;
+
+       /* Try to reopen namespace - should fail with ENOENT since it's inactive */
+       fd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
+       ASSERT_LT(fd, 0);
+       /* Should fail with ENOENT (namespace inactive) or ESTALE */
+       ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
+}
+
 TEST_HARNESS_MAIN