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 <[email protected]>
---
 .../testing/selftests/nfsd/nfsd_netlink_listener.c | 39 ++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/tools/testing/selftests/nfsd/nfsd_netlink_listener.c 
b/tools/testing/selftests/nfsd/nfsd_netlink_listener.c
index d0f4258f905d..106360f87b99 100644
--- a/tools/testing/selftests/nfsd/nfsd_netlink_listener.c
+++ b/tools/testing/selftests/nfsd/nfsd_netlink_listener.c
@@ -1243,6 +1243,45 @@ TEST_F(nfsd_listener, rpcb_retry_next_request)
        EXPECT_STREQ("", last_extack);
 }
 
+/*
+ * The same rule on the way out. Removing a listener unregisters it, so a
+ * rpcbind that stops answering used to cost one timeout for each listener
+ * removed. Register one listener while the stub answers, silence the stub,
+ * remove it and count; then do the same with three.
+ *
+ * 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.
+ */
+TEST_F(nfsd_listener, rpcb_unreg_stop_after_failure)
+{
+       int before, one, three, off;
+       char attrs[192];
+
+       off = put_listener(attrs, 0, "tcp", TEST_PORT);
+       ASSERT_EQ(0, listener_set(attrs, off));
+
+       rpcb_stub_set_mode(RPCB_STUB_SILENT);
+       before = rpcb_calls();
+       ASSERT_EQ(0, listener_set(NULL, 0));
+       one = rpcb_calls() - before;
+       ASSERT_GT(one, 0);
+
+       rpcb_stub_set_mode(RPCB_STUB_ACCEPT);
+       off = put_listener(attrs, 0, "tcp", TEST_PORT);
+       off = put_listener(attrs, off, "tcp", TEST_PORT + 1);
+       off = put_listener(attrs, off, "tcp", TEST_PORT + 2);
+       ASSERT_EQ(0, listener_set(attrs, off));
+
+       rpcb_stub_set_mode(RPCB_STUB_SILENT);
+       before = rpcb_calls();
+       ASSERT_EQ(0, listener_set(NULL, 0));
+       three = rpcb_calls() - before;
+
+       /* the second and third removals must not reach rpcbind at all */
+       EXPECT_LE(three, one);
+}
+
 /* ===================== threads / -EBUSY semantics ===================== */
 
 TEST_F(nfsd_listener, sem_busy_on_change)

-- 
2.55.0


Reply via email to