Skip to content

Commit ee86103

Browse files
committed
selftests/namespace: second threaded active reference count test
Test that a namespace remains active while a thread holds an fd to it. Even after the thread exits, the namespace should remain active as long as another thread holds a file descriptor to it. Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-68-2e6f823ebdc0@kernel.org Reviewed-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent 29f083c commit ee86103

1 file changed

Lines changed: 99 additions & 0 deletions

File tree

tools/testing/selftests/namespaces/ns_active_ref_test.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,4 +2251,103 @@ TEST(thread_ns_inactive_after_exit)
22512251
ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
22522252
}
22532253

2254+
/*
2255+
* Test that a namespace remains active while a thread holds an fd to it.
2256+
* Even after the thread exits, the namespace should remain active as long as
2257+
* another thread holds a file descriptor to it.
2258+
*/
2259+
TEST(thread_ns_fd_keeps_active)
2260+
{
2261+
pthread_t thread;
2262+
struct thread_ns_info info;
2263+
struct file_handle *handle;
2264+
int pipefd[2];
2265+
int syncpipe[2];
2266+
int ret;
2267+
char sync_byte;
2268+
char buf[sizeof(*handle) + MAX_HANDLE_SZ];
2269+
2270+
ASSERT_EQ(pipe(pipefd), 0);
2271+
ASSERT_EQ(pipe(syncpipe), 0);
2272+
2273+
info.pipefd = pipefd[1];
2274+
info.syncfd_read = syncpipe[0];
2275+
info.syncfd_write = -1;
2276+
info.exit_code = -1;
2277+
2278+
/* Create thread that will create a namespace */
2279+
ret = pthread_create(&thread, NULL, thread_create_namespace, &info);
2280+
ASSERT_EQ(ret, 0);
2281+
2282+
/* Read namespace ID from thread */
2283+
__u64 ns_id;
2284+
ret = read(pipefd[0], &ns_id, sizeof(ns_id));
2285+
if (ret != sizeof(ns_id)) {
2286+
sync_byte = 'X';
2287+
write(syncpipe[1], &sync_byte, 1);
2288+
pthread_join(thread, NULL);
2289+
close(pipefd[0]);
2290+
close(pipefd[1]);
2291+
close(syncpipe[0]);
2292+
close(syncpipe[1]);
2293+
SKIP(return, "Failed to read namespace ID from thread");
2294+
}
2295+
2296+
TH_LOG("Thread created namespace with ID %llu", (unsigned long long)ns_id);
2297+
2298+
/* Construct file handle */
2299+
handle = (struct file_handle *)buf;
2300+
handle->handle_bytes = sizeof(struct nsfs_file_handle);
2301+
handle->handle_type = FILEID_NSFS;
2302+
struct nsfs_file_handle *fh = (struct nsfs_file_handle *)handle->f_handle;
2303+
fh->ns_id = ns_id;
2304+
fh->ns_type = 0;
2305+
fh->ns_inum = 0;
2306+
2307+
/* Open namespace while thread is alive */
2308+
TH_LOG("Opening namespace while thread is alive");
2309+
int nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
2310+
ASSERT_GE(nsfd, 0);
2311+
2312+
/* Signal thread to exit */
2313+
TH_LOG("Signaling thread to exit");
2314+
sync_byte = 'X';
2315+
write(syncpipe[1], &sync_byte, 1);
2316+
close(syncpipe[1]);
2317+
2318+
/* Wait for thread to exit */
2319+
pthread_join(thread, NULL);
2320+
close(pipefd[0]);
2321+
close(pipefd[1]);
2322+
close(syncpipe[0]);
2323+
2324+
if (info.exit_code != 0) {
2325+
close(nsfd);
2326+
SKIP(return, "Thread failed to create namespace");
2327+
}
2328+
2329+
TH_LOG("Thread exited, but main thread holds fd - namespace should remain active");
2330+
2331+
/* Namespace should still be active because we hold an fd */
2332+
int nsfd2 = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
2333+
ASSERT_GE(nsfd2, 0);
2334+
2335+
/* Verify it's the same namespace */
2336+
struct stat st1, st2;
2337+
ASSERT_EQ(fstat(nsfd, &st1), 0);
2338+
ASSERT_EQ(fstat(nsfd2, &st2), 0);
2339+
ASSERT_EQ(st1.st_ino, st2.st_ino);
2340+
close(nsfd2);
2341+
2342+
TH_LOG("Closing fd - namespace should become inactive");
2343+
close(nsfd);
2344+
2345+
/* Now namespace should be inactive */
2346+
nsfd = open_by_handle_at(FD_NSFS_ROOT, handle, O_RDONLY);
2347+
ASSERT_LT(nsfd, 0);
2348+
/* Should fail with ENOENT (inactive) or ESTALE (gone) */
2349+
TH_LOG("Namespace inactive as expected: %s (errno=%d)", strerror(errno), errno);
2350+
ASSERT_TRUE(errno == ENOENT || errno == ESTALE);
2351+
}
2352+
22542353
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)