Linux NFS development
 help / color / mirror / Atom feed
* [PATCH pynfs v2] RPLY14: reconnect before retransmitting the call
@ 2026-09-24 13:39 Jeff Layton
  0 siblings, 0 replies; only message in thread
From: Jeff Layton @ 2026-09-24 13:39 UTC (permalink / raw)
  To: Calum Mackay
  Cc: Chuck Lever, NeilBrown, Olga Kornievskaia, Dai Ngo, Tom Talpey,
	linux-nfs, Jeff Layton

This test recently started failing with a change to the Linux kernel,
but we believe that the test is wrong. This test replays the same call
with the same XID over the same socket without reconnecting in between.

RFC7530, section 3.1.1 says:

   When processing an NFSv4 request received over a reliable transport
   such as TCP, the NFSv4 server MUST NOT silently drop the request,
   except if the established transport connection has been broken.
   Given such a contract between NFSv4 clients and servers, clients MUST
   NOT retry a request unless one or both of the following are true:

   o  The transport connection has been broken
   o  The procedure being retried is the NULL procedure

Reconnect the socket before retransmitting the request.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Changes in v2:
- Drop redundant comment
- Quote RFC7530 in the changelog as justification
- Link to v1: https://lore.kernel.org/r/20260923-rply14-v1-1-f653557909af@kernel.org
---
 nfs4.0/lib/rpc/rpc.py           | 25 +++++++++++++++++++++++++
 nfs4.0/servertests/st_replay.py |  7 +++++--
 2 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/nfs4.0/lib/rpc/rpc.py b/nfs4.0/lib/rpc/rpc.py
index 7a80241aa127..c530847a46d9 100644
--- a/nfs4.0/lib/rpc/rpc.py
+++ b/nfs4.0/lib/rpc/rpc.py
@@ -315,6 +315,31 @@ class RPCClient(object):
         out.settimeout(self.timeout)
         self.lock.release()
         return out
+
+    def reconnect_same_port(self):
+        """Drop the current connection and reconnect from the same local
+        port, so the server sees a new transport with an unchanged
+        (address, port) cache key. Used to test duplicate reply cache
+        behavior across connections.
+
+        The old socket is reset (RST) rather than closed gracefully: a
+        graceful close leaves the 4-tuple unusable until the server
+        also closes, while an RST frees the source port immediately.
+        """
+        t = threading.currentThread()
+        self.lock.acquire()
+        old = self._socket[t]
+        saddr = old.getsockname()
+        old.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER,
+                       struct.pack('ii', 1, 0))
+        old.close()
+        out = self._socket[t] = socket.socket(self.af, socket.SOCK_STREAM)
+        out.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        out.bind(saddr)
+        out.connect((self.remotehost, self.remoteport))
+        out.settimeout(self.timeout)
+        self.lock.release()
+        return out
         
     def send(self, procedure, data=b'', program=None, version=None):
         """Send an RPC call to the server
diff --git a/nfs4.0/servertests/st_replay.py b/nfs4.0/servertests/st_replay.py
index 48e5363432ec..dc375bbc78a4 100644
--- a/nfs4.0/servertests/st_replay.py
+++ b/nfs4.0/servertests/st_replay.py
@@ -4,7 +4,7 @@ from xdrdef.nfs4_type import *
 import nfs_ops
 op = nfs_ops.NFS4ops()
 
-def _replay(env, c, ops, error=NFS4_OK):
+def _replay(env, c, ops, error=NFS4_OK, newconn=False):
     # Can send in an error list, but replays must return same error as orig
     if type(error) is list:
         check_funct = check
@@ -18,6 +18,9 @@ def _replay(env, c, ops, error=NFS4_OK):
     try:
         c.get_new_xid = lambda : xid
 
+        if newconn:
+            c.reconnect_same_port()
+
         # note: this is really cheesy: we happen to know the current
         # Linux server implementation will drop a replay if it comes
         # "too quickly" (<.02 seconds).
@@ -260,4 +263,4 @@ def testMkdirReplay(t, env):
     c = env.c1
     c.init_connection()
     ops = c.go_home() + [op.create(createtype4(NF4DIR), t.word(), {})]
-    _replay(env, c, ops)
+    _replay(env, c, ops, newconn=True)

---
base-commit: cd4701827a8261fedbfb4c6e39029fb9671321a6
change-id: 20260923-rply14-d24b334cd6fa

Best regards,
-- 
Jeff Layton <jlayton@kernel.org>


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-24 13:39 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24 13:39 [PATCH pynfs v2] RPLY14: reconnect before retransmitting the call Jeff Layton

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox