diff --git a/sys/fs/nfs/nfsport.h b/sys/fs/nfs/nfsport.h index eb6db8a8b2e..d2c259fbacb 100644 --- a/sys/fs/nfs/nfsport.h +++ b/sys/fs/nfs/nfsport.h @@ -590,6 +590,7 @@ struct nfst_rec { #define NFSNST_NEWSTATE 0x1 #define NFSNST_REVOKE 0x2 #define NFSNST_GOTSTATE 0x4 +#define NFSNST_RECLAIMED 0x8 /* * This structure is linked onto nfsrv_stablefirst for the duration of diff --git a/sys/fs/nfsserver/nfs_nfsdstate.c b/sys/fs/nfsserver/nfs_nfsdstate.c index 9f68dd49c3e..f8d71903f54 100644 --- a/sys/fs/nfsserver/nfs_nfsdstate.c +++ b/sys/fs/nfsserver/nfs_nfsdstate.c @@ -136,6 +136,7 @@ static int nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp, static u_int32_t nfsrv_nextclientindex(void); static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp); static void nfsrv_markstable(struct nfsclient *clp); +static void nfsrv_markreclaim(struct nfsclient *clp); static int nfsrv_checkstable(struct nfsclient *clp); static int nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, struct vnode *vp, NFSPROC_T *p); @@ -4091,7 +4092,26 @@ static int nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp, u_int32_t flags) { - int error = 0; + int error = 0, notreclaimed; + struct nfsrv_stable *sp; + + if ((nfsrv_stablefirst.nsf_flags & (NFSNSF_UPDATEDONE | + NFSNSF_GRACEOVER)) == 0) { + /* + * First, check to see if all of the clients have done a + * ReclaimComplete. If so, grace can end now. + */ + notreclaimed = 0; + LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { + if ((sp->nst_flag & NFSNST_RECLAIMED) == 0) { + notreclaimed = 1; + break; + } + } + if (notreclaimed == 0) + nfsrv_stablefirst.nsf_flags |= (NFSNSF_GRACEOVER | + NFSNSF_NEEDLOCK); + } if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0) { if (flags & NFSLCK_RECLAIM) { @@ -4748,6 +4768,32 @@ nfsrv_markstable(struct nfsclient *clp) sp->nst_clp = clp; } +/* + * This function is called when a NFSv4.1 client does a ReclaimComplete. + * Very similar to nfsrv_markstable(), except for the flag being set. + */ +static void +nfsrv_markreclaim(struct nfsclient *clp) +{ + struct nfsrv_stable *sp; + + /* + * First find the client structure. + */ + LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) { + if (sp->nst_len == clp->lc_idlen && + !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len)) + break; + } + if (sp == LIST_END(&nfsrv_stablefirst.nsf_head)) + return; + + /* + * Now, just set the flag. + */ + sp->nst_flag |= NFSNST_RECLAIMED; +} + /* * This function is called for a reclaim, to see if it gets grace. * It returns 0 if a reclaim is allowed, 1 otherwise. @@ -5904,8 +5950,10 @@ nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd) /* Check to see if reclaim complete has already happened. */ if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0) error = NFSERR_COMPLETEALREADY; - else + else { sep->sess_clp->lc_flags |= LCL_RECLAIMCOMPLETE; + nfsrv_markreclaim(sep->sess_clp); + } NFSUNLOCKSESSION(shp); NFSUNLOCKSTATE(); return (error);