From owner-dev-commits-src-branches@freebsd.org Wed May 12 02:19:10 2021 Return-Path: Delivered-To: dev-commits-src-branches@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id C6DF362DE80; Wed, 12 May 2021 02:19:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4Ffz4Z5JQzz3LL4; Wed, 12 May 2021 02:19:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A90872328D; Wed, 12 May 2021 02:19:10 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 14C2JASC046632; Wed, 12 May 2021 02:19:10 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 14C2JAxG046631; Wed, 12 May 2021 02:19:10 GMT (envelope-from git) Date: Wed, 12 May 2021 02:19:10 GMT Message-Id: <202105120219.14C2JAxG046631@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Rick Macklem Subject: git: 7e35a8a28c6f - stable/13 - nfscl: return delegations in the NFS VOP_RECLAIM() MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: 7e35a8a28c6f719ad4e8b8e33bbc0b7a5901e008 Auto-Submitted: auto-generated X-BeenThere: dev-commits-src-branches@freebsd.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Commits to the stable branches of the FreeBSD src repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 12 May 2021 02:19:10 -0000 The branch stable/13 has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=7e35a8a28c6f719ad4e8b8e33bbc0b7a5901e008 commit 7e35a8a28c6f719ad4e8b8e33bbc0b7a5901e008 Author: Rick Macklem AuthorDate: 2021-04-26 00:57:55 +0000 Commit: Rick Macklem CommitDate: 2021-05-12 02:15:26 +0000 nfscl: return delegations in the NFS VOP_RECLAIM() After a vnode is recycled it can no longer be acquired via vfs_hash_get() and, as such, a delegation for the vnode cannot be recalled. In the unlikely event that a delegation still exists when the vnode is being recycled, return the delegation since it will no longer be recallable. Until you have this patch in your NFSv4 client, you should consider avoiding the use of delegations. (cherry picked from commit aad780464fad1e32c97316515a4044d661413a6b) --- sys/fs/nfs/nfs_var.h | 1 + sys/fs/nfsclient/nfs_clnode.c | 10 ++++++++- sys/fs/nfsclient/nfs_clstate.c | 49 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 23ba0e3893db..f23d56050449 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -604,6 +604,7 @@ void nfscl_lockinit(struct nfsv4lock *); void nfscl_lockexcl(struct nfsv4lock *, void *); void nfscl_lockunlock(struct nfsv4lock *); void nfscl_lockderef(struct nfsv4lock *); +void nfscl_delegreturnvp(vnode_t, NFSPROC_T *); void nfscl_docb(struct nfsrv_descript *, NFSPROC_T *); void nfscl_releasealllocks(struct nfsclclient *, vnode_t, NFSPROC_T *, void *, int); diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c index a59b96bf3c8b..43c2286726f7 100644 --- a/sys/fs/nfsclient/nfs_clnode.c +++ b/sys/fs/nfsclient/nfs_clnode.c @@ -303,7 +303,7 @@ ncl_reclaim(struct vop_reclaim_args *ap) ncl_releasesillyrename(vp, td); NFSUNLOCKNODE(np); - if (NFS_ISV4(vp) && vp->v_type == VREG) + if (NFS_ISV4(vp) && vp->v_type == VREG) { /* * We can now safely close any remaining NFSv4 Opens for * this file. Most opens will have already been closed by @@ -311,6 +311,14 @@ ncl_reclaim(struct vop_reclaim_args *ap) * called, so we need to do it again here. */ (void) nfsrpc_close(vp, 1, td); + /* + * It it unlikely a delegation will still exist, but + * if one does, it must be returned before calling + * vfs_hash_remove(), since it cannot be recalled once the + * nfs node is no longer available. + */ + nfscl_delegreturnvp(vp, td); + } vfs_hash_remove(vp); diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c index 6cff58331c97..bbc1c6ccbc2f 100644 --- a/sys/fs/nfsclient/nfs_clstate.c +++ b/sys/fs/nfsclient/nfs_clstate.c @@ -152,7 +152,8 @@ static int nfscl_trylock(struct nfsmount *, vnode_t , u_int8_t *, struct ucred *, NFSPROC_T *); static int nfsrpc_reopen(struct nfsmount *, u_int8_t *, int, u_int32_t, struct nfsclopen *, struct nfscldeleg **, struct ucred *, NFSPROC_T *); -static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *); +static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *, + bool); static int nfscl_errmap(struct nfsrv_descript *, u_int32_t); static void nfscl_cleanup_common(struct nfsclclient *, u_int8_t *); static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *, @@ -1622,12 +1623,13 @@ nfscl_cleandeleg(struct nfscldeleg *dp) * Free a delegation. */ static void -nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp) +nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp, bool freeit) { TAILQ_REMOVE(hdp, dp, nfsdl_list); LIST_REMOVE(dp, nfsdl_hash); - free(dp, M_NFSCLDELEG); + if (freeit) + free(dp, M_NFSCLDELEG); nfsstatsv1.cldelegates--; nfscl_delegcnt--; } @@ -1725,7 +1727,7 @@ nfscl_expireclient(struct nfsclclient *clp, struct nfsmount *nmp, printf("nfsv4 expired locks lost\n"); } nfscl_cleandeleg(dp); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); dp = ndp; } if (!TAILQ_EMPTY(&clp->nfsc_deleg)) @@ -2257,7 +2259,7 @@ nfscl_recover(struct nfsclclient *clp, bool *retokp, struct ucred *cred, * away. Ouch!! */ nfscl_cleandeleg(dp); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } else { LIST_INSERT_HEAD(&extra_open, nop, nfso_list); } @@ -3280,11 +3282,40 @@ nfscl_delegreturnall(struct nfsclclient *clp, NFSPROC_T *p) TAILQ_FOREACH_SAFE(dp, &clp->nfsc_deleg, nfsdl_list, ndp) { nfscl_cleandeleg(dp); (void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } NFSFREECRED(cred); } +/* + * Return any delegation for this vp. + */ +void +nfscl_delegreturnvp(vnode_t vp, NFSPROC_T *p) +{ + struct nfsclclient *clp; + struct nfscldeleg *dp; + struct ucred *cred; + struct nfsnode *np; + + np = VTONFS(vp); + cred = newnfs_getcred(); + NFSLOCKCLSTATE(); + clp = VFSTONFS(vp->v_mount)->nm_clp; + dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, + np->n_fhp->nfh_len); + if (dp != NULL) { + nfscl_cleandeleg(dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, false); + NFSUNLOCKCLSTATE(); + newnfs_copycred(&dp->nfsdl_cred, cred); + nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p); + free(dp, M_NFSCLDELEG); + } else + NFSUNLOCKCLSTATE(); + NFSFREECRED(cred); +} + /* * Do a callback RPC. */ @@ -4515,7 +4546,7 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp) *stp = dp->nfsdl_stateid; retcnt = 1; nfscl_cleandeleg(dp); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } if (igotlock) nfsv4_unlock(&clp->nfsc_lock, 0); @@ -4615,7 +4646,7 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp, retcnt++; *gotfdp = 1; nfscl_cleandeleg(dp); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } if (igotlock) { nfsv4_unlock(&clp->nfsc_lock, 0); @@ -4651,7 +4682,7 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp, retcnt++; *gottdp = 1; nfscl_cleandeleg(dp); - nfscl_freedeleg(&clp->nfsc_deleg, dp); + nfscl_freedeleg(&clp->nfsc_deleg, dp, true); } } NFSUNLOCKCLSTATE();