From: Tim Menninger <tmenninger@everpuredata.com>
To: Trond Myklebust <trondmy@kernel.org>, Anna Schumaker <anna@kernel.org>
Cc: linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org,
Eric Badger <ebadger@everpuredata.com>,
Jon Curley <jcurley@everpuredata.com>,
stable@vger.kernel.org
Subject: [PATCH] NFSv4/pNFS: Preserve layoutreturn seqid while lsegs drain
Date: Mon, 21 Sep 2026 23:55:20 +0000 [thread overview]
Message-ID: <20260921235520.502987-1-tmenninger@everpuredata.com> (raw)
Commit e20772cbdf46 ("NFSv4/pNFS: Fix a layoutget livelock loop")
changed pnfs_set_plh_return_info() so that a zero seq argument is
replaced with the current layout stateid seqid. This ensures that a
pending layout return has a nonzero plh_return_seq and does not
continually invalidate newly acquired layout segments.
pnfs_cache_lseg_for_layoutreturn() already passed zero to this helper.
Before e20772cbdf46, that call updated the pending return iomode and
NFS_LAYOUT_RETURN_REQUESTED state, but did not change plh_return_seq.
After e20772cbdf46, it also snapshots the current layout stateid seqid.
This is problematic when an lseg that was already selected for return
takes time to drain its outstanding references. For example, suppose a
return is established with plh_return_seq S. While an lseg covered by
that return is draining, successful LAYOUTGET operations can advance the
layout stateid to T, where T is newer than S.
When the lseg's final reference is released, the path is:
pnfs_put_lseg()
-> pnfs_cache_lseg_for_layoutreturn()
-> pnfs_set_plh_return_info(seq=0) # advances plh_return_seq
-> pnfs_put_layout_hdr()
-> pnfs_layoutreturn_before_put_layout_hdr()
-> pnfs_layout_need_return()
-> pnfs_mark_layout_stateid_return(seq=lo->plh_return_seq)
-> pnfs_mark_matching_lsegs_return(seq)
The zero argument causes pnfs_cache_lseg_for_layoutreturn() to advance
plh_return_seq from S to T. pnfs_layout_need_return() then uses T as the
upper bound when selecting lsegs for return, so layout segments acquired
after the original return was requested can also be invalidated and have
their I/O cancelled.
Under sustained I/O, those cancellations cause more lsegs to drain,
whose final puts can advance the return boundary again. This can form a
positive feedback loop in which newly acquired layouts are repeatedly
invalidated and cancelled.
This was observed on a one-client one-DS system under sustained
direct-read I/O over pNFS/RDMA after restarting the nfs service on the
DS, where the repeated layout invalidation and cancellation caused
severe throughput collapse.
When the draining lseg is already covered by plh_return_seq, pass the
existing return seqid to pnfs_set_plh_return_info() instead of zero so
that caching the lseg does not move the return boundary. If there is no
return seqid yet, or the lseg is newer than the recorded boundary,
retain the existing behavior and snapshot the current layout stateid.
Fixes: e20772cbdf46 ("NFSv4/pNFS: Fix a layoutget livelock loop")
Cc: stable@vger.kernel.org
Signed-off-by: Tim Menninger <tmenninger@everpuredata.com>
---
fs/nfs/pnfs.c | 10 +++++++++-
1 file changed, 9 insertions(+), 1 deletion(-)
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c
index 4f9c0f639014..69b085482921 100644
--- a/fs/nfs/pnfs.c
+++ b/fs/nfs/pnfs.c
@@ -596,9 +596,17 @@ static bool
pnfs_cache_lseg_for_layoutreturn(struct pnfs_layout_hdr *lo,
struct pnfs_layout_segment *lseg)
{
+ u32 seq = lo->plh_return_seq;
+
if (test_and_clear_bit(NFS_LSEG_LAYOUTRETURN, &lseg->pls_flags) &&
pnfs_layout_is_valid(lo)) {
- pnfs_set_plh_return_info(lo, lseg->pls_range.iomode, 0);
+ /*
+ * Avoid resnapshotting the current layout stateid for an lseg that
+ * is already covered by the pending return.
+ */
+ if (!seq || pnfs_seqid_is_newer(lseg->pls_seq, seq))
+ seq = 0;
+ pnfs_set_plh_return_info(lo, lseg->pls_range.iomode, seq);
list_move_tail(&lseg->pls_list, &lo->plh_return_segs);
return true;
}
--
2.34.1
next reply other threads:[~2026-09-21 23:55 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-21 23:55 Tim Menninger [this message]
2026-10-13 13:53 ` Tim Menninger
2026-10-13 19:09 ` Anna Schumaker
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=20260921235520.502987-1-tmenninger@everpuredata.com \
--to=tmenninger@everpuredata.com \
--cc=anna@kernel.org \
--cc=ebadger@everpuredata.com \
--cc=jcurley@everpuredata.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=stable@vger.kernel.org \
--cc=trondmy@kernel.org \
/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
all inboxes | Powered by JetHome®