mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Jeff Layton <jlayton@kernel.org>
To: Chuck Lever <cel@kernel.org>, NeilBrown <neil@brown.name>,
	 Olga Kornievskaia <okorniev@redhat.com>,
	Dai Ngo <Dai.Ngo@oracle.com>,  Tom Talpey <tom@talpey.com>,
	Shuah Khan <shuah@kernel.org>
Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org,
	 linux-kselftest@vger.kernel.org,
	Jeff Layton <jlayton@kernel.org>
Subject: [PATCH v2 8/8] selftests/nfsd: add a cross-namespace control-plane soak
Date: Tue, 22 Sep 2026 07:34:09 -0400	[thread overview]
Message-ID: <20260922-nfsd-per-net-mutex-v2-8-4a5da8243a73@kernel.org> (raw)
In-Reply-To: <20260922-nfsd-per-net-mutex-v2-0-4a5da8243a73@kernel.org>

Drive the NFSD control plane from many namespaces at once, to exercise
every edge of the lock nesting:

	nn->nfsd_mutex -> nfsd_global_mutex -> nfsd_file_cache_mutex

Each worker owns a namespace and churns between "no serv" and "serv with
threads", mixing in the operations that cross into the host-wide locks:

  start/stop a server	nn -> global (nfsd_users 0->1->0, notifiers)
			   -> cache (cache init/shutdown)
  empty LISTENER_SET	creates and destroys a serv in one call, so the
			   host-wide refcount goes 0->1->0 on its own
  nfsd.fh/flush		the cache lock with nothing else held
  read filecache	likewise
  read pool_stats	nn, reached through svc_info.mutex

Random churn alone is a weak race finder, so the run ends with
synchronized rounds where every namespace attempts the host-wide 0->1
transition at the same instant. That window only opened up once the
per-namespace lock stopped serializing namespaces against each other.

The test asserts little by itself; the result that matters is that the
kernel did not warn. The taint word is sampled before and after and a
newly set TAINT_WARN fails the run, which catches lockdep splats,
WARN_ON()s and refcount saturation alike. Add PROVE_LOCKING and friends
to the config, and log a note if lockdep looks absent.

Two things can silently gut the coverage, so both are reported rather
than left to look like a pass:

  - without lockdep there is very little for the kernel to complain
    about;
  - a server already running outside these namespaces pins the
    host-wide refcount above zero for the whole run, so the 0->1
    transition the synchronized rounds are built around never happens.

Each worker leaves only NFSv4.1 enabled. A fresh namespace has v3 on,
which makes nfsd_needs_lockd() true, and the lockd that comes up then
waits out an RPC timeout against an rpcbind that is not there on every
single server start.

Every namespace binds the same port; they are isolated, so that must
work, and a bind failure is a louder signal than a silent pass. Sized
from nproc, capped at 8 namespaces and 5s of churn by default, and
tunable with NFSD_STRESS_WORKERS and NFSD_STRESS_SECS. The barrier waits
with a deadline so a worker that dies cannot wedge the run, and the test
carries an explicit timeout because the harness otherwise caps it at
TEST_TIMEOUT_DEFAULT.

Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 tools/testing/selftests/nfsd/.gitignore          |   1 +
 tools/testing/selftests/nfsd/Makefile            |   1 +
 tools/testing/selftests/nfsd/config              |   6 +
 tools/testing/selftests/nfsd/nfsd_netns_stress.c | 572 +++++++++++++++++++++++
 tools/testing/selftests/nfsd/settings            |   2 +-
 5 files changed, 581 insertions(+), 1 deletion(-)

diff --git a/tools/testing/selftests/nfsd/.gitignore b/tools/testing/selftests/nfsd/.gitignore
index 0304b80eb844..2347491c634d 100644
--- a/tools/testing/selftests/nfsd/.gitignore
+++ b/tools/testing/selftests/nfsd/.gitignore
@@ -1,2 +1,3 @@
 nfsd_netlink_listener
 nfsd_netns_isolation
+nfsd_netns_stress
diff --git a/tools/testing/selftests/nfsd/Makefile b/tools/testing/selftests/nfsd/Makefile
index 2b7c44c3fb00..b29bf642c0ad 100644
--- a/tools/testing/selftests/nfsd/Makefile
+++ b/tools/testing/selftests/nfsd/Makefile
@@ -3,5 +3,6 @@ CFLAGS += $(KHDR_INCLUDES) -Wall
 
 TEST_GEN_PROGS := nfsd_netlink_listener
 TEST_GEN_PROGS += nfsd_netns_isolation
+TEST_GEN_PROGS += nfsd_netns_stress
 
 include ../lib.mk
diff --git a/tools/testing/selftests/nfsd/config b/tools/testing/selftests/nfsd/config
index 0eef03af3503..c6407806b58b 100644
--- a/tools/testing/selftests/nfsd/config
+++ b/tools/testing/selftests/nfsd/config
@@ -12,3 +12,9 @@ CONFIG_INOTIFY_USER=y
 CONFIG_SUNRPC=y
 CONFIG_NFSD=y
 CONFIG_NFSD_V4=y
+
+# nfsd_netns_stress leans on lockdep to find anything; without these the
+# soak still runs but proves very little.
+CONFIG_PROVE_LOCKING=y
+CONFIG_DEBUG_MUTEXES=y
+CONFIG_DEBUG_ATOMIC_SLEEP=y
diff --git a/tools/testing/selftests/nfsd/nfsd_netns_stress.c b/tools/testing/selftests/nfsd/nfsd_netns_stress.c
new file mode 100644
index 000000000000..7ca278a5d4a0
--- /dev/null
+++ b/tools/testing/selftests/nfsd/nfsd_netns_stress.c
@@ -0,0 +1,572 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Concurrency soak for the NFSD control plane across network namespaces.
+ *
+ * NFSD's control plane is serialized by three locks, nested in this order:
+ *
+ *	nn->nfsd_mutex  ->  nfsd_global_mutex  ->  nfsd_file_cache_mutex
+ *
+ * Most of what used to be one module-wide mutex is now per-namespace, so
+ * namespaces run their control planes in parallel and only meet on the
+ * host-wide bits: the refcount that brings the open file cache and the
+ * NFSv4 global tables up and down, and the address-notifier registration.
+ *
+ * This test exists to drive every one of those edges at once from many
+ * namespaces. It asserts little by itself -- the point is to give lockdep
+ * something to work with, so it is close to worthless without
+ * CONFIG_PROVE_LOCKING=y. What it does check is that the kernel did not
+ * warn: the taint word is sampled before and after, and a newly set
+ * TAINT_WARN fails the run. That catches lockdep splats, WARN_ON()s and
+ * refcount saturation alike.
+ *
+ * Each worker drives these, which between them cover every edge:
+ *
+ *   start a server	nn -> global (nfsd_users 0->1, notifiers 0->1)
+ *			   -> cache (nfsd_file_cache_init)
+ *   stop a server	nn -> global (1->0) -> cache (cache_shutdown)
+ *   empty LISTENER_SET	creates and destroys a serv in one call, so the
+ *			   host-wide refcount goes 0->1->0 on its own
+ *   nfsd.fh/flush	the cache lock with nothing else held
+ *   read filecache	likewise
+ *   read pool_stats	nn, reached through svc_info.mutex
+ *
+ * Random churn alone is a weak race finder, so the run ends with
+ * synchronized rounds where every worker attempts the host-wide 0->1
+ * transition at the same instant. That is the window that only opened up
+ * once the per-namespace lock stopped serializing namespaces against each
+ * other.
+ *
+ * Tunable with NFSD_STRESS_WORKERS and NFSD_STRESS_SECS.
+ */
+#define _GNU_SOURCE
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <sched.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <net/if.h>
+#include <netinet/in.h>
+
+#include "../kselftest_harness.h"
+#include "nfsd_netlink.h"
+
+#define NFSD_MNT		"/mnt/nfsd"
+#define EXPKEY_FLUSH		"/proc/net/rpc/nfsd.fh/flush"
+
+/*
+ * Every worker binds the same port. They are in different namespaces, so
+ * that has to work; if isolation ever breaks, the second bind fails loudly
+ * rather than the test quietly passing.
+ */
+#define STRESS_PORT		20049
+
+#define DEFAULT_WORKERS		8
+#define DEFAULT_SECS		5
+#define MAX_WORKERS		64
+#define SYNC_ROUNDS		20
+#define BARRIER_TIMEOUT_SEC	30
+
+/*
+ * Generous: the harness caps a test at TEST_TIMEOUT_DEFAULT otherwise, and
+ * the churn duration is tunable.
+ */
+#define SOAK_TIMEOUT_SEC	600
+
+#define TAINT_WARN_BIT		(1UL << 9)
+
+/* Worker exit codes. */
+#define WORKER_OK		0
+#define WORKER_FAIL		1
+#define WORKER_NO_SETUP		2
+
+/* ------------------- cross-process barrier ------------------- */
+
+struct barrier {
+	unsigned int n;
+	unsigned int count;
+	unsigned int generation;
+	unsigned int aborted;	/* latched: a rendezvous was never completed */
+};
+
+/*
+ * Spin with a deadline rather than blocking, so a worker that dies cannot
+ * wedge the run.
+ *
+ * The first waiter to give up latches ->aborted, which kills the barrier
+ * for good: every later call returns at once instead of waiting out its
+ * own deadline. Without that latch a single missing worker costs
+ * BARRIER_TIMEOUT_SEC on every remaining rendezvous -- three per round,
+ * SYNC_ROUNDS rounds -- which runs into tens of minutes before the
+ * harness timeout fires.
+ *
+ * A giving-up waiter leaves its ->count increment behind. That is fine:
+ * once ->aborted is set nothing reads ->count again.
+ *
+ * Returns false if the rendezvous did not happen.
+ */
+static bool barrier_wait(struct barrier *b)
+{
+	unsigned int gen = __atomic_load_n(&b->generation, __ATOMIC_ACQUIRE);
+	time_t deadline = time(NULL) + BARRIER_TIMEOUT_SEC;
+
+	if (__atomic_load_n(&b->aborted, __ATOMIC_ACQUIRE))
+		return false;
+
+	if (__atomic_add_fetch(&b->count, 1, __ATOMIC_ACQ_REL) == b->n) {
+		__atomic_store_n(&b->count, 0, __ATOMIC_RELEASE);
+		__atomic_add_fetch(&b->generation, 1, __ATOMIC_ACQ_REL);
+		return true;
+	}
+	while (__atomic_load_n(&b->generation, __ATOMIC_ACQUIRE) == gen) {
+		if (__atomic_load_n(&b->aborted, __ATOMIC_ACQUIRE))
+			return false;
+		if (time(NULL) > deadline) {
+			__atomic_store_n(&b->aborted, 1, __ATOMIC_RELEASE);
+			return false;
+		}
+		sched_yield();
+	}
+	return true;
+}
+
+/* ------------------- namespace setup ------------------- */
+
+static int netns_enter(void)
+{
+	struct ifreq ifr = {0};
+	int s;
+
+	if (unshare(CLONE_NEWNET | CLONE_NEWNS) < 0)
+		return -errno;
+	if (mount("", "/", NULL, MS_REC | MS_PRIVATE, NULL) < 0)
+		return -errno;
+	if (mount("tmpfs", "/mnt", "tmpfs", 0, NULL) < 0)
+		return -errno;
+	if (mkdir(NFSD_MNT, 0755) < 0)
+		return -errno;
+	if (mount("nfsd", NFSD_MNT, "nfsd", 0, NULL) < 0)
+		return -errno;
+
+	s = socket(AF_INET, SOCK_DGRAM, 0);
+	if (s < 0)
+		return -errno;
+	strcpy(ifr.ifr_name, "lo");
+	if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
+		close(s);
+		return -errno;
+	}
+	ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
+	if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
+		close(s);
+		return -errno;
+	}
+	close(s);
+
+	nfsd_family = genl_resolve_nfsd();
+	if (nfsd_family < 0)
+		return -ENOENT;
+	return 0;
+}
+
+/* ------------------- the operations ------------------- */
+
+static int read_nfsd_file(const char *name)
+{
+	char path[128], buf[4096];
+	int fd, n;
+
+	snprintf(path, sizeof(path), "%s/%s", NFSD_MNT, name);
+	fd = open(path, O_RDONLY);
+	if (fd < 0)
+		return -errno;
+	do {
+		n = read(fd, buf, sizeof(buf));
+	} while (n > 0);
+	close(fd);
+	return n < 0 ? -errno : 0;
+}
+
+/*
+ * The only userspace trigger that reaches nfsd_file_cache_purge(), and so
+ * the only one that takes the file cache lock with no other nfsd lock
+ * held. NFSD_CMD_CACHE_FLUSH does not get there: cache_purge() never calls
+ * the cache_detail's ->flush hook.
+ */
+static int expkey_flush(void)
+{
+	int fd = open(EXPKEY_FLUSH, O_WRONLY);
+	int n;
+
+	if (fd < 0)
+		return -errno;
+	n = write(fd, "1\n", 2);
+	close(fd);
+	return n < 0 ? -errno : 0;
+}
+
+/* Create a serv and tear it straight back down inside one call. */
+static int serv_cycle(void)
+{
+	return listener_set(NULL, 0);
+}
+
+static int server_up(int nthreads)
+{
+	char attrs[128];
+	int off, ret;
+
+	off = put_listener(attrs, 0, "tcp", STRESS_PORT);
+	off = put_attr(attrs, off, NFSD_A_SERVER_SOCK_USERSPACE_RPCBIND,
+		       NULL, 0);
+	ret = listener_set(attrs, off);
+	if (ret)
+		return ret;
+	return threads_set(nthreads);
+}
+
+/* threads_set(0) drops the last thread, which destroys the serv with it. */
+static int server_down(void)
+{
+	return threads_set(0);
+}
+
+/* ------------------- the worker ------------------- */
+
+struct worker_err {
+	const char *op;
+	int err;
+};
+
+static struct worker_err worker_fault;
+
+static bool fail(const char *op, int err)
+{
+	if (err == 0)
+		return false;
+	worker_fault.op = op;
+	worker_fault.err = err;
+	return true;
+}
+
+/*
+ * Random churn between "no serv" and "serv with threads", with the
+ * lock-crossing reads and flushes mixed in at both ends. Every call here
+ * is one that must succeed in the state it is issued from, so any error is
+ * a real failure rather than an expected race.
+ */
+static bool worker_churn(time_t deadline)
+{
+	bool up = false;
+
+	while (time(NULL) < deadline) {
+		int r = random() % 8;
+
+		if (!up) {
+			switch (r) {
+			case 0:
+			case 1:
+				if (fail("serv_cycle", serv_cycle()))
+					return false;
+				break;
+			case 2:
+				if (fail("version_set", version_set_only(4, 1)))
+					return false;
+				break;
+			case 3:
+				if (fail("flush", expkey_flush()))
+					return false;
+				break;
+			case 4:
+				if (fail("filecache", read_nfsd_file("filecache")))
+					return false;
+				break;
+			case 5:
+				if (fail("pool_stats", read_nfsd_file("pool_stats")))
+					return false;
+				break;
+			default:
+				if (fail("server_up", server_up(1 + random() % 3)))
+					return false;
+				up = true;
+				break;
+			}
+		} else {
+			switch (r) {
+			case 0:
+				if (fail("flush", expkey_flush()))
+					return false;
+				break;
+			case 1:
+				if (fail("filecache", read_nfsd_file("filecache")))
+					return false;
+				break;
+			case 2:
+				if (fail("pool_stats", read_nfsd_file("pool_stats")))
+					return false;
+				break;
+			case 3:
+				if (fail("threads_set", threads_set(1 + random() % 3)))
+					return false;
+				break;
+			default:
+				if (fail("server_down", server_down()))
+					return false;
+				up = false;
+				break;
+			}
+		}
+	}
+
+	if (up && fail("server_down", server_down()))
+		return false;
+	return true;
+}
+
+/*
+ * Every worker arrives at the barrier with no serv, so the host-wide
+ * refcount is at zero, then they all try to take it to one together. The
+ * second barrier lines up the drop back to zero the same way.
+ */
+static bool worker_sync_rounds(struct barrier *b)
+{
+	int i;
+
+	for (i = 0; i < SYNC_ROUNDS; i++) {
+		/*
+		 * A failed rendezvous means a peer is gone, which its own
+		 * exit status already reports. Stop the rounds rather than
+		 * stalling on every remaining barrier.
+		 */
+		if (!barrier_wait(b))
+			return true;
+		if (fail("sync server_up", server_up(1)))
+			return false;
+
+		if (!barrier_wait(b))
+			return true;
+		if (fail("sync flush", expkey_flush()))
+			return false;
+
+		if (!barrier_wait(b))
+			return true;
+		if (fail("sync server_down", server_down()))
+			return false;
+	}
+	return true;
+}
+
+static int worker(int idx, struct barrier *b, unsigned int secs)
+{
+	int ret = netns_enter();
+
+	if (ret) {
+		/*
+		 * Report setup trouble rather than a failure: a restricted
+		 * environment is not a kernel bug.
+		 */
+		fprintf(stderr, "netns %d: setup: %s\n", idx, strerror(-ret));
+		return WORKER_NO_SETUP;
+	}
+
+	/*
+	 * Leave only NFSv4.1 enabled. A fresh namespace has v3 on, which
+	 * makes nfsd_needs_lockd() true, and the lockd that comes up then
+	 * tries to reach an rpcbind that is not there -- so every server
+	 * start waits out an RPC timeout and floods the log. The version
+	 * set sticks across serv teardown, so once is enough.
+	 */
+	ret = version_set_only(4, 1);
+	if (ret) {
+		fprintf(stderr, "netns %d: version_set: %s\n", idx,
+			strerror(-ret));
+		return WORKER_FAIL;
+	}
+
+	srandom(getpid() ^ (unsigned int)time(NULL));
+
+	if (!worker_churn(time(NULL) + secs))
+		goto fault;
+	if (!worker_sync_rounds(b))
+		goto fault;
+	return WORKER_OK;
+
+fault:
+	fprintf(stderr, "netns %d: %s: %s\n", idx, worker_fault.op,
+		strerror(-worker_fault.err));
+	server_down();
+	return WORKER_FAIL;
+}
+
+/*
+ * Threads running outside the test's namespaces. Any at all pin the
+ * host-wide refcount above zero for the whole run, so the 0->1 transition
+ * the synchronized rounds are built around never happens.
+ */
+static int nfsd_threads_here(void)
+{
+	char buf[32] = "";
+	int fd = open("/proc/fs/nfsd/threads", O_RDONLY);
+	int n = 0;
+
+	if (fd < 0)
+		return 0;
+	if (read(fd, buf, sizeof(buf) - 1) > 0)
+		n = atoi(buf);
+	close(fd);
+	return n;
+}
+
+/* ------------------- taint ------------------- */
+
+static unsigned long read_taint(void)
+{
+	unsigned long v = 0;
+	FILE *f = fopen("/proc/sys/kernel/tainted", "r");
+
+	if (!f)
+		return 0;
+	if (fscanf(f, "%lu", &v) != 1)
+		v = 0;
+	fclose(f);
+	return v;
+}
+
+/* ------------------- the test ------------------- */
+
+static unsigned int env_uint(const char *name, unsigned int def, unsigned int max)
+{
+	const char *s = getenv(name);
+	unsigned long v;
+
+	if (!s || !*s)
+		return def;
+	v = strtoul(s, NULL, 0);
+	if (v == 0 || v > max)
+		return def;
+	return (unsigned int)v;
+}
+
+FIXTURE(soak) {
+	int unused;
+};
+
+FIXTURE_SETUP(soak) { }
+FIXTURE_TEARDOWN(soak) { }
+
+TEST_F_TIMEOUT(soak, netns_control_plane_soak, SOAK_TIMEOUT_SEC)
+{
+	unsigned long taint_before, taint_after;
+	unsigned int workers, secs;
+	pid_t pid[MAX_WORKERS];
+	int failed = 0, skipped = 0;
+	unsigned int aborted;
+	struct barrier *b;
+	unsigned int i;
+	long ncpu;
+
+	if (geteuid() != 0)
+		SKIP(return, "must be run as root");
+
+	ncpu = sysconf(_SC_NPROCESSORS_ONLN);
+	if (ncpu < 2)
+		ncpu = 2;
+	workers = env_uint("NFSD_STRESS_WORKERS",
+			   ncpu < DEFAULT_WORKERS ? (unsigned int)ncpu
+						  : DEFAULT_WORKERS,
+			   MAX_WORKERS);
+	secs = env_uint("NFSD_STRESS_SECS", DEFAULT_SECS, 3600);
+
+	b = mmap(NULL, sizeof(*b), PROT_READ | PROT_WRITE,
+		 MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	ASSERT_NE(MAP_FAILED, b);
+	b->n = workers;
+	b->count = 0;
+	b->generation = 0;
+	b->aborted = 0;
+
+	TH_LOG("%u namespaces, %us of churn then %d synchronized rounds",
+	       workers, secs, SYNC_ROUNDS);
+
+	/*
+	 * A server already running outside these namespaces holds the
+	 * host-wide refcount above zero for the whole run, so the 0->1
+	 * transition the synchronized rounds are built around never
+	 * happens. Worth saying out loud rather than reporting coverage
+	 * that was not there.
+	 */
+	if (nfsd_threads_here() > 0)
+		TH_LOG("note: nfsd runs outside these namespaces; refcount never hits 0");
+
+	taint_before = read_taint();
+
+	for (i = 0; i < workers; i++) {
+		pid[i] = fork();
+		ASSERT_GE(pid[i], 0);
+		if (pid[i] == 0)
+			_exit(worker(i, b, secs));
+	}
+
+	for (i = 0; i < workers; i++) {
+		int status = 0;
+
+		waitpid(pid[i], &status, 0);
+		if (!WIFEXITED(status)) {
+			failed++;
+			continue;
+		}
+		if (WEXITSTATUS(status) == WORKER_FAIL)
+			failed++;
+		else if (WEXITSTATUS(status) == WORKER_NO_SETUP)
+			skipped++;
+	}
+
+	taint_after = read_taint();
+	aborted = __atomic_load_n(&b->aborted, __ATOMIC_ACQUIRE);
+	munmap(b, sizeof(*b));
+
+	if (skipped == (int)workers)
+		SKIP(return, "no worker could set up a private nfsd namespace");
+
+	EXPECT_EQ(0, failed)
+		TH_LOG("%d of %u namespaces reported an error", failed, workers);
+
+	/*
+	 * A namespace that never reached the rounds -- one that could not
+	 * set up, say -- leaves the rest with nobody to meet. Say so: the
+	 * synchronized part did not run to completion.
+	 */
+	if (aborted)
+		TH_LOG("note: synchronized rounds cut short; a namespace did not arrive");
+
+	/*
+	 * The real result. Without CONFIG_PROVE_LOCKING there is very little
+	 * here for the kernel to complain about, so say so rather than
+	 * letting a quiet pass look like coverage.
+	 */
+	EXPECT_EQ(0, (taint_after & ~taint_before) & TAINT_WARN_BIT)
+		TH_LOG("kernel warned during the run (taint %#lx -> %#lx); check dmesg",
+		       taint_before, taint_after);
+
+	/*
+	 * lockdep_proc_init() puts these in procfs, not debugfs, and
+	 * lockdep_chains is the one that appears only with
+	 * CONFIG_PROVE_LOCKING -- the part that validates ordering rather
+	 * than merely tracking. Root-only, but so is this test.
+	 */
+	if (access("/proc/lockdep_chains", R_OK) != 0)
+		TH_LOG("note: CONFIG_PROVE_LOCKING looks absent; this proves little");
+}
+
+TEST_HARNESS_MAIN
diff --git a/tools/testing/selftests/nfsd/settings b/tools/testing/selftests/nfsd/settings
index 694d70710ff0..a62d2fa1275c 100644
--- a/tools/testing/selftests/nfsd/settings
+++ b/tools/testing/selftests/nfsd/settings
@@ -1 +1 @@
-timeout=300
+timeout=600

-- 
2.55.0


  parent reply	other threads:[~2026-09-22 11:34 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-22 11:34 [PATCH v2 0/8] nfsd: reduce the scope of the nfsd_mutex Jeff Layton
2026-09-22 11:34 ` [PATCH v2 1/8] nfsd: clear NFSD_NET_UP before dropping the generic resource reference Jeff Layton
2026-09-22 11:34 ` [PATCH v2 2/8] nfsd: make max_blksize a per-namespace setting Jeff Layton
2026-09-22 11:34 ` [PATCH v2 3/8] nfsd: move the control plane to a per-namespace mutex Jeff Layton
2026-09-22 11:34 ` [PATCH v2 4/8] nfsd: rename nfsd_mutex to nfsd_global_mutex Jeff Layton
2026-09-22 11:34 ` [PATCH v2 5/8] nfsd: give the open file cache its own mutex Jeff Layton
2026-09-22 11:34 ` [PATCH v2 6/8] selftests/nfsd: factor the netlink plumbing into a shared header Jeff Layton
2026-09-22 11:34 ` [PATCH v2 7/8] selftests/nfsd: add cross-namespace isolation tests Jeff Layton
2026-09-22 11:34 ` Jeff Layton [this message]
2026-09-22 15:50 ` [PATCH v2 0/8] nfsd: reduce the scope of the nfsd_mutex Chuck Lever

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260922-nfsd-per-net-mutex-v2-8-4a5da8243a73@kernel.org \
    --to=jlayton@kernel.org \
    --cc=Dai.Ngo@oracle.com \
    --cc=cel@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-nfs@vger.kernel.org \
    --cc=neil@brown.name \
    --cc=okorniev@redhat.com \
    --cc=shuah@kernel.org \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®