From: Jeff Layton <jlayton@kernel.org>
To: Calum Mackay <calum.mackay@oracle.com>
Cc: Chuck Lever <chuck.lever@vger.kernel.org>,
NeilBrown <neil@brown.name>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
linux-nfs@vger.kernel.org, Jeff Layton <jlayton@kernel.org>
Subject: [PATCH pynfs] RPLY14: reconnect before retransmitting the call
Date: Wed, 23 Sep 2026 13:43:48 -0400 [thread overview]
Message-ID: <20260923-rply14-v1-1-f653557909af@kernel.org> (raw)
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.
There is language in RFC1813 that implies that a reconnect is necessary
on a retransmit on a reliable transport like TCP. Change the test to
reconnect the socket before retransmitting.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
nfs4.0/lib/rpc/rpc.py | 25 +++++++++++++++++++++++++
nfs4.0/servertests/st_replay.py | 10 ++++++++--
2 files changed, 33 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..fc8282151909 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,12 @@ def _replay(env, c, ops, error=NFS4_OK):
try:
c.get_new_xid = lambda : xid
+ if newconn:
+ # Reconnect from the same source port before replaying:
+ # servers may drop a retransmit that arrives on the same
+ # connection as the original call.
+ 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 +266,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>
next reply other threads:[~2026-09-23 17:43 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-23 17:43 Jeff Layton [this message]
2026-09-24 13:14 ` [PATCH pynfs] RPLY14: reconnect before retransmitting the call Chuck Lever
2026-09-24 21:46 ` NeilBrown
2026-09-25 14:04 ` 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=20260923-rply14-v1-1-f653557909af@kernel.org \
--to=jlayton@kernel.org \
--cc=Dai.Ngo@oracle.com \
--cc=calum.mackay@oracle.com \
--cc=chuck.lever@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--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