diff options
author | Trond Myklebust <trond.myklebust@hammerspace.com> | 2021-07-26 13:58:49 +0200 |
---|---|---|
committer | Anna Schumaker <Anna.Schumaker@Netapp.com> | 2021-08-09 22:57:04 +0200 |
commit | e20772cbdf463c12088837e5a08bde1b876bfd25 (patch) | |
tree | 3e81ab8676c16bbba86480779448ba71fcef885f /fs/nfs/pnfs.c | |
parent | SUNRPC: Convert rpc_client refcount to use refcount_t (diff) | |
download | linux-e20772cbdf463c12088837e5a08bde1b876bfd25.tar.xz linux-e20772cbdf463c12088837e5a08bde1b876bfd25.zip |
NFSv4/pNFS: Fix a layoutget livelock loop
If NFS_LAYOUT_RETURN_REQUESTED is set, but there is no value set for
the layout plh_return_seq, we can end up in a livelock loop in which
every layout segment retrieved by a new call to layoutget is immediately
invalidated by pnfs_layout_need_return().
To get around this, we should just set plh_return_seq to the current
value of the layout stateid's seqid.
Fixes: d474f96104bd ("NFS: Don't return layout segments that are in use")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
Diffstat (limited to 'fs/nfs/pnfs.c')
-rw-r--r-- | fs/nfs/pnfs.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index ef14ea0b6ab8..da5cacad6979 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c @@ -347,11 +347,15 @@ pnfs_set_plh_return_info(struct pnfs_layout_hdr *lo, enum pnfs_iomode iomode, iomode = IOMODE_ANY; lo->plh_return_iomode = iomode; set_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags); - if (seq != 0) { - WARN_ON_ONCE(lo->plh_return_seq != 0 && lo->plh_return_seq != seq); + /* + * We must set lo->plh_return_seq to avoid livelocks with + * pnfs_layout_need_return() + */ + if (seq == 0) + seq = be32_to_cpu(lo->plh_stateid.seqid); + if (!lo->plh_return_seq || pnfs_seqid_is_newer(seq, lo->plh_return_seq)) lo->plh_return_seq = seq; - pnfs_barrier_update(lo, seq); - } + pnfs_barrier_update(lo, seq); } static void |