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 v2] RPLY14: reconnect before retransmitting the call
Date: Thu, 24 Sep 2026 09:39:45 -0400 [thread overview]
Message-ID: <20260924-rply14-v2-1-7a6a9e33e878@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.
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>
reply other threads:[~2026-09-24 13:39 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260924-rply14-v2-1-7a6a9e33e878@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