git: 75d71cf8df8c - stable/12 - nfscl: Fix another deadlock related to the NFSv4 clientID lock

From: Rick Macklem <rmacklem_at_FreeBSD.org>
Date: Tue, 19 Oct 2021 03:49:49 UTC
The branch stable/12 has been updated by rmacklem:

URL: https://cgit.FreeBSD.org/src/commit/?id=75d71cf8df8c83b2b2bc3a16ef66a540a2ebac70

commit 75d71cf8df8c83b2b2bc3a16ef66a540a2ebac70
Author:     Rick Macklem <rmacklem@FreeBSD.org>
AuthorDate: 2021-10-13 00:21:01 +0000
Commit:     Rick Macklem <rmacklem@FreeBSD.org>
CommitDate: 2021-10-19 03:46:00 +0000

    nfscl: Fix another deadlock related to the NFSv4 clientID lock
    
    Without this patch, it is possible to hang the NFSv4 client,
    when a rename/remove is being done on a file where the client
    holds a delegation, if pNFS is being used.  For a delegation
    to be returned, dirty data blocks must be flushed to the NFSv4
    server.  When pNFS is in use, a shared lock on the clientID
    must be acquired while doing a write to the DS(s).
    However, if rename/remove is doing the delegation return
    an exclusive lock will be acquired on the clientID, preventing
    the write to the DS(s) from acquiring a shared lock on the clientID.
    
    This patch stops rename/remove from doing a delegation return
    if pNFS is enabled.  Since doing delegation return in the same
    compound as rename/remove is only an optimization, not doing
    so should not cause problems.
    
    This problem was detected during a recent NFSv4 interoperability
    testing event held by the IETF working group.
    
    (cherry picked from commit b82168e657d378ff86ea18c4f03b98aac9ee9bb3)
---
 sys/fs/nfsclient/nfs_clstate.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 92688fcfbe28..5f35e4e708e9 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -4480,6 +4480,8 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
 	int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
 
 	nmp = VFSTONFS(vnode_mount(vp));
+	if (NFSHASPNFS(nmp))
+		return (retcnt);
 	np = VTONFS(vp);
 	NFSLOCKCLSTATE();
 	/*
@@ -4579,6 +4581,8 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
 	nmp = VFSTONFS(vnode_mount(fvp));
 	*gotfdp = 0;
 	*gottdp = 0;
+	if (NFSHASPNFS(nmp))
+		return (retcnt);
 	NFSLOCKCLSTATE();
 	/*
 	 * Loop around waiting for: