aboutsummaryrefslogtreecommitdiff
path: root/sys/fs/nfsclient/nfs_clstate.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient/nfs_clstate.c')
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c49
1 files changed, 40 insertions, 9 deletions
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,12 +3282,41 @@ 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.
*/
void
@@ -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();