aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/fs/nfsserver/nfs_nfsdstate.c89
1 files changed, 75 insertions, 14 deletions
diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c
index 102af9bb2951..d790ab974d07 100644
--- a/sys/fs/nfsserver/nfs_nfsdstate.c
+++ b/sys/fs/nfsserver/nfs_nfsdstate.c
@@ -253,6 +253,7 @@ static void nfsrv_issuedelegation(struct vnode *vp, struct nfsclient *clp,
nfsv4stateid_t *delegstateidp);
static void nfsrv_clientlock(bool mlocked);
static void nfsrv_clientunlock(bool mlocked);
+static void nfsrv_freelockifnotinuse(struct nfslockfile *lfp);
/*
* Lock the client structure, either with the mutex or the exclusive nfsd lock.
@@ -1537,20 +1538,13 @@ nfsrv_freedeleglist(struct nfsstatehead *sthp)
static void
nfsrv_freedeleg(struct nfsstate *stp)
{
- struct nfslockfile *lfp;
LIST_REMOVE(stp, ls_hash);
LIST_REMOVE(stp, ls_list);
LIST_REMOVE(stp, ls_file);
if ((stp->ls_flags & NFSLCK_DELEGWRITE) != 0)
nfsrv_writedelegcnt--;
- lfp = stp->ls_lfp;
- if (LIST_EMPTY(&lfp->lf_open) &&
- LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) &&
- LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) &&
- lfp->lf_usecount == 0 &&
- nfsv4_testlock(&lfp->lf_locallock_lck) == 0)
- nfsrv_freenfslockfile(lfp);
+ nfsrv_freelockifnotinuse(stp->ls_lfp);
free(stp, M_NFSDSTATE);
VNET(nfsstatsv1_p)->srvdelegates--;
nfsrv_openpluslock--;
@@ -1632,12 +1626,7 @@ nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p)
* If there are locks associated with the open, the
* nfslockfile structure can be freed via nfsrv_freelockowner().
*/
- if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) &&
- LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) &&
- LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) &&
- lfp->lf_usecount == 0 &&
- nfsv4_testlock(&lfp->lf_locallock_lck) == 0)
- nfsrv_freenfslockfile(lfp);
+ nfsrv_freelockifnotinuse(lfp);
free(stp, M_NFSDSTATE);
VNET(nfsstatsv1_p)->srvopens--;
nfsrv_openpluslock--;
@@ -8881,3 +8870,75 @@ nfsrv_removedeleg(fhandle_t *fhp, struct nfsrv_descript *nd, NFSPROC_T *p)
}
NFSUNLOCKSTATE();
}
+
+/*
+ * Free the nfslockfile structure if not in use.
+ */
+static void
+nfsrv_freelockifnotinuse(struct nfslockfile *lfp)
+{
+
+ /*
+ * The nfslockfile is freed here if there are no locks
+ * associated with the open.
+ * If there are locks associated with the open, the
+ * nfslockfile structure can be freed via nfsrv_freelockowner().
+ */
+ if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) &&
+ LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) &&
+ LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) &&
+ lfp->lf_usecount == 0 &&
+ nfsv4_testlock(&lfp->lf_locallock_lck) == 0)
+ nfsrv_freenfslockfile(lfp);
+}
+
+/*
+ * Free stranded open/lock/delegation/layouts.
+ * (These become stranded if the file has been deleted.)
+ */
+void
+nfsrv_freestrandedstate(struct nfsrvfh *nfp)
+{
+ struct nfslockfile *lfp;
+ struct nfsstate *stp, *nstp;
+ struct nfslayouthash *lhyp;
+ struct nfslayout *lyp, *nlyp;
+ fhandle_t *fhp;
+
+ if (nfp->nfsrvfh_len != NFSX_MYFH)
+ return;
+ fhp = (fhandle_t *)nfp->nfsrvfh_data;
+ NFSLOCKSTATE();
+ if (nfsrv_getlockfile(0, NULL, &lfp, fhp, 0) < 0) {
+ NFSUNLOCKSTATE();
+ return;
+ }
+ lfp->lf_usecount++; /* So nfsrv_freeopen() does not free it. */
+ /* Note that nfsrv_freeopen() will also free the byte range locks. */
+ LIST_FOREACH_SAFE(stp, &lfp->lf_open, ls_file, nstp)
+ nfsrv_freeopen(stp, NULL, 0, curthread);
+
+ /*
+ * Normally, a delegation will have been recalled when the file is
+ * removed. However, get rid of any that have somehow been
+ * left stranded.
+ */
+ LIST_FOREACH_SAFE(stp, &lfp->lf_deleg, ls_file, nstp)
+ nfsrv_freedeleg(stp);
+
+ /* Get rid of the nfslockfile, if no longer in use. */
+ lfp->lf_usecount--;
+ nfsrv_freelockifnotinuse(lfp);
+ NFSUNLOCKSTATE();
+
+ /* Free any layouts for the pNFS server case. */
+ if (nfsrv_devidcnt == 0)
+ return;
+ lhyp = NFSLAYOUTHASH(fhp);
+ NFSLOCKLAYOUT(lhyp);
+ TAILQ_FOREACH_SAFE(lyp, &lhyp->list, lay_list, nlyp) {
+ if (NFSBCMP(&lyp->lay_fh, fhp, sizeof(*fhp)) == 0)
+ nfsrv_freelayout(&lhyp->list, lyp);
+ }
+ NFSUNLOCKLAYOUT(lhyp);
+}