| Age | Commit message (Collapse) | Author |
|
Cover the flag that moves rpcbind registration to the caller.
rpcb_userspace_no_traffic is the one that matters. The errno says nothing
about whether the kernel talked to rpcbind, but the stub counters do: a
request that carries the flag must leave both at zero, which is what shows
that svc_bind() and svc_register() were both skipped.
The rest cover the reply and the ownership rule:
- rpcb_userspace_reply. The ack flag, a non-empty program list, and the
listener that came up. nfslocalio is hidden, so it must be absent.
- rpcb_userspace_no_v4_udp. NFSv3 must be offered and must not carry
no-udp; NFSv4 carries it, or the test skips where v4 is not built.
- rpcb_userspace_nfsacl_follows_nfs. CONFIG_NFSD_V3_ACL is invisible to the
test, so assert only that nfsacl v3 implies nfs v3.
- rpcb_userspace_busy and rpcb_userspace_busy_reverse. Ownership cannot
change under a live serv, in either direction.
- rpcb_userspace_unflagged_teardown and its reverse. Teardown destroys the
serv, so it is exempt from that rule in both directions. The follow-on
listener_set is what proves the old serv went away rather than merely
losing its listeners.
- rpcb_userspace_portlist_busy. The legacy portlist add-fd write is
refused against a flagged serv and still works against a kernel-owned
one. nfsdfs is mounted in the test's netns, so the write cannot reach
the host's nfsd.
- rpcb_userspace_teardown. Create and destroy a flagged serv three times,
then confirm that a kernel-owned serv still reaches rpcbind. An
unbalanced rpcb_put_local() would break the last step.
- rpcb_userspace_many_listeners. Forty listeners, which is more than
GENLMSG_DEFAULT_SIZE would have held. A reply sized from that constant
instead of from its contents returns -EMSGSIZE with every listener
already up.
genl_request_reply() grew an attribute argument, because listener_set now
answers with a reply message rather than a bare ack.
listener_set_rpcb() checks nlmsg_len against the recv() count before
parsing. Forty listeners fit in its buffer, but a reply near
NFSD_NL_LISTENER_MAX would not, and the parse loops trust nlmsg_len.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260915-nfsd-norpcb-v3-5-3c60d49ade02@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
|
|
Cover the teardown side of the same rule. Remove one listener, then three,
with the stub silent, and compare what it saw. Three removals must not cost
three timeouts.
Both measurements also pay the svc_unregister() sweep that
nfsd_destroy_serv() runs once the last listener is gone, so that cancels
out of the comparison. The listeners are registered with the stub
answering, so each one has an entry to remove.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-15-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
|
|
Cover the change that stops a listener_set request from registering after
rpcbind stops answering.
RPCB_STUB_SILENT is new. It reads a call and writes nothing back, so the
kernel waits out its own timeout. RPCB_STUB_REFUSE cannot serve here: a
refusal is an answer, and the count ignores it on purpose.
Every procedure but the NULL one is silenced, so an unregistration goes
unanswered as well. The NULL one has to be answered:
rpcb_create_af_local() builds its client without RPC_CLNT_CREATE_NOPING, so
rpc_create() pings at creation. Silencing that ping too would fail the
AF_LOCAL client, send rpcb_create_local() on to the loopback client of
rpcb_create_local_net(), and leave the stub seeing one call per request no
matter how many listeners it carried.
- rpcb_stop_after_failure. Ask for one listener, then for three, and
compare what the stub saw. Three entries must not cost three times as
much.
- rpcb_silent_set_complete. The entry that finds rpcbind silent is the one
that pays the timeout, and with v3 enabled it is the only entry whose
listener would be lost. Require that a three-entry request brings up all
three, succeeds, and warns.
- rpcb_v4_only_bounded. The case that needs the count rather than a failed
listener. version_set_only() makes the server v4-only, so vs_rpcb_optnl
discards every error and every listener comes up. Require that the
listeners are present, that the ack warns about them, and that three
entries do not cost three round trips.
- rpcb_retry_next_request. The stop lasts for one request. After the stub
starts to answer, the next request must reach rpcbind again.
The counts these tests compare include the unregistrations that the
teardown between the two measurements issues. The preceding patches bound
that direction too, so the sweeps stay at one timeout rather than one per
program and version.
version_set_only() is new. NFSD_CMD_VERSION_SET clears every version
before it reads the request, so one nest leaves the server v4-only. It
returns -EBUSY once a serv exists, so the test calls it first.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-14-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
|
|
The creation of a listener registers with rpcbind.
svc_xprt_create_from_sa() passes flags of 0, so pmap_register is true in
svc_setup_socket(). A fresh netns has no rpcbind. Every registration
therefore waits out the local rpcbind timeout, once for each program and
version, and the registration failure then takes the listener down. The
host's rpcbind is not an option either. svc_rpcb_setup() opens with a call
to svc_unregister(), which would clear the host's nfsd entries.
Serve rpcbind from inside the namespace instead. The abstract AF_LOCAL
name that the kernel tries first is per-netns, because
unix_find_abstract() takes a struct net. Bind "\0/run/rpcbind.sock" and
fork a minimal responder:
- the responder never decodes arguments. The NULL procedure gets an empty
success, and SET and UNSET get TRUE.
- the responder answers RPCBVERS_4 as well as RPCBVERS_2. A v4 refusal
makes __svc_rpcb_register6() return -EAFNOSUPPORT, which would leave
every IPv6 listener unregistered.
- the responder counts accepted connections and received calls in a page
that it shares with the test, and reads its mode from that page on every
call. The mode lives there rather than in the child so that a test can
change it with a serv already up: killing and restarting the stub would
close the connection the kernel holds, and rpcb_register_call() issues
UNSET over AF_LOCAL with RPC_TASK_NOCONNECT, so the next call would fail
at once with -ENOTCONN instead of waiting out a timeout.
- PR_SET_PDEATHSIG plus an explicit kill in FIXTURE_TEARDOWN make sure that
no stub outlives its test.
With the stub in place, add the tests that need a serv. These cover the
create, add and remove paths and the LISTENER_GET round trips: tcp, udp,
several listeners at once, an idempotent re-set, the removal of a subset,
the destruction of a serv from an empty list, and IPv6. Two more tests
cover the empty-list request and the -EBUSY refusal after THREADS_SET has
started threads.
The netlink socket asks for NETLINK_EXT_ACK, so that the tests can read the
extack message. It also asks for NETLINK_CAP_ACK, so that the kernel does
not echo the request back and the TLVs sit at a fixed offset.
FIXTURE_TEARDOWN drops whatever a test left running. A listener holds a
reference to the netns, and that netns outlives the test process. Threads
pin the listeners. Anything left up therefore leaks the namespace.
Several of these tests exist to catch a revert, not to describe the
interface. The errno alone shows none of them:
- val_reject_keeps_listeners. An unknown transport name ends in
-EPROTONOSUPPORT either way, because svc_xprt_create_from_sa() returns
that error too. The difference is the state that it leaves. Without the
up-front check, nfsd_nl_listener_set_doit() has already destroyed the
listeners that did not match by the time the name fails.
- val_bad_transport. This test now also requires that the stub saw no
traffic. A request that reaches svc_xprt_create_from_sa() has run
nfsd_create_serv(). svc_bind() then pings rpcbind at client creation and
sweeps stale entries with svc_unregister(). Silence at the stub is
therefore what shows that the kernel refused the request up front.
- val_second_entry_bad. This test now also sends a LISTENER_GET.
svc_xprt_create_from_sa() also returns -EAFNOSUPPORT for the bad entry,
and the doit keeps the listeners that it did create. The well-formed tcp
entry ahead of it would otherwise still be up.
- sem_register_refused. This test puts the stub in a mode that answers
RPCBPROC_SET with FALSE. rpcb_register_call() turns that answer into
-EACCES, svc_register() then fails, and svc_setup_socket() creates no
listener. The bare errno does not show that, because a bind can return
-EACCES too, so the test reads the listener set back and requires that
it is empty.
- sem_create_failure_extack. This test squats on the port first, so the
listener cannot bind. The extack must then name the transport that
failed.
- func_empty_destroys. This test uses the connection count. LISTENER_GET
replies empty both for a destroyed serv and for a live serv with no
permsocks. But only nfsd_destroy_serv() reaches
svc_xprt_destroy_all(..., unregister=true) -> svc_rpcb_cleanup() ->
rpcb_put_local(), which drops the last user and shuts the local client
down. The next serv has to connect again.
- sem_busy_on_change and sem_busy_on_remove read the listeners back,
because -EBUSY says nothing about what the doit did before it returned.
find_listener() matches the address as well as the transport, the family
and the port. Every listener here is created on loopback, so a reply that
names 0.0.0.0 has to fail.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-13-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
|
|
Add regression tests for the NFSD_CMD_LISTENER_SET checks that
nfsd_nl_validate_listeners() runs before the code takes nfsd_mutex. The
tests cover a bad transport name, an absent transport name, a missing
address, a truncated or unsupported sockaddr, a bad address family, a
malformed entry behind a well-formed one, and more than
NFSD_NL_LISTENER_MAX entries. One more test sends a LISTENER_GET to an
empty netns.
None of these requests reach nfsd_create_serv(), so nothing here creates a
serv or registers with rpcbind. The tests that do need a serv come next,
with a stub.
The tests use kselftest_harness.h, so each test runs in its own net and
mount namespace. /run is masked there. unix_find_bsd() resolves by inode
and takes no struct net, so a connect to "/var/run/rpcbind.sock" from this
netns would otherwise reach the rpcbind on the host. svc_rpcb_setup()
opens with a call to svc_unregister(), which would then clear the host's
nfsd registrations.
The config fragment must therefore cover the fixture as well as nfsd:
NAMESPACES and NET_NS for the unshare(), SHMEM and TMPFS for the mask, and
UNIX for the AF_LOCAL rpcbind client. Without them, every test skips.
Add the new directory to the NFSD MAINTAINERS entry, which does not cover
tools/testing/selftests/ today.
Assisted-by: LLM
Signed-off-by: Jeff Layton <jlayton@kernel.org>
Link: https://patch.msgid.link/20260901-nfsd-nl-hang-v5-12-a540d86668b0@kernel.org
Signed-off-by: Chuck Lever <cel@kernel.org>
|