--- //depot/vendor/freebsd/src/sys/nfsserver/nfs_serv.c 2006/10/26 12:42:15 +++ //depot/user/rwatson/nfs/src/sys/nfsserver/nfs_serv.c 2006/11/07 17:21:59 @@ -137,11 +137,10 @@ SYSCTL_STRUCT(_vfs_nfsrv, NFS_NFSRVSTATS, nfsrvstats, CTLFLAG_RD, &nfsrvstats, nfsrvstats, "S,nfsrvstats"); -static int nfsrv_access_withgiant(struct vnode *vp, int flags, - struct ucred *cred, int rdonly, struct thread *td, - int override); -static int nfsrv_access(struct vnode *, int, struct ucred *, int, - struct thread *, int); +static int nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, + int rdonly, struct thread *td, int override); +static int nfsrv_access_locked(struct vnode *, int, struct ucred *, + int, struct thread *, int); static void nfsrvw_coalesce(struct nfsrv_descript *, struct nfsrv_descript *); @@ -181,6 +180,7 @@ struct vattr vattr, *vap = &vattr; u_long testmode, nfsmode; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -199,9 +199,9 @@ } nfsmode = fxdr_unsigned(u_int32_t, *tl); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); if ((nfsmode & NFSV3ACCESS_READ) && - nfsrv_access_withgiant(vp, VREAD, cred, rdonly, td, 0)) + nfsrv_access(vp, VREAD, cred, rdonly, td, 0)) nfsmode &= ~NFSV3ACCESS_READ; if (vp->v_type == VDIR) testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND | @@ -209,18 +209,18 @@ else testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND); if ((nfsmode & testmode) && - nfsrv_access_withgiant(vp, VWRITE, cred, rdonly, td, 0)) + nfsrv_access(vp, VWRITE, cred, rdonly, td, 0)) nfsmode &= ~testmode; if (vp->v_type == VDIR) testmode = NFSV3ACCESS_LOOKUP; else testmode = NFSV3ACCESS_EXECUTE; if ((nfsmode & testmode) && - nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0)) + nfsrv_access(vp, VEXEC, cred, rdonly, td, 0)) nfsmode &= ~testmode; getret = VOP_GETATTR(vp, vap, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED); @@ -231,9 +231,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -259,6 +259,7 @@ caddr_t bpos; int error = 0, rdonly; struct mbuf *mb, *mreq; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -272,10 +273,10 @@ goto nfsmout; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VOP_GETATTR(vp, vap, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)); @@ -292,9 +293,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -325,6 +326,7 @@ struct mbuf *mb, *mreq; struct timespec guard; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -336,10 +338,10 @@ goto out; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); VATTR_NULL(vap); if (v3) { @@ -398,7 +400,7 @@ */ if (v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = preat_ret = VOP_GETATTR(vp, &preat, cred, td); if (!error && gcheck && (preat.va_ctime.tv_sec != guard.tv_sec || @@ -406,7 +408,7 @@ error = NFSERR_NOT_SYNC; if (error) { vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_WCCDATA(v3)); @@ -415,7 +417,7 @@ error = 0; goto nfsmout; } - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } NFSD_LOCK_ASSERT(); @@ -433,15 +435,15 @@ if (vp->v_type == VDIR) { error = EISDIR; goto out; - } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, - td, 0)) != 0) + } else if ((error = nfsrv_access_locked(vp, VWRITE, cred, + rdonly, td, 0)) != 0) goto out; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VOP_SETATTR(vp, vap, cred, td); postat_ret = VOP_GETATTR(vp, vap, cred, td); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); if (!error) error = postat_ret; @@ -449,9 +451,9 @@ NFSD_LOCK_ASSERT(); if (vp != NULL) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } @@ -470,11 +472,11 @@ nfsmout: NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); if (vp) vput(vp); vn_finished_write(mp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); return(error); } @@ -521,8 +523,11 @@ /* * namei failure, only dirp to cleanup. Clear out garbarge from * structure in case macros jump to nfsmout. + * + * XXXRW: For now, use Giant unconditionally during name lookup, + * rather than deal with complexity of conditional Giant acqusition + * as moving across the name space. */ - NFSD_UNLOCK(); mtx_lock(&Giant); /* VFS */ if (error) { @@ -696,6 +701,7 @@ nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -746,7 +752,7 @@ goto nfsmout; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); if (vp->v_type != VLNK) { if (v3) error = EINVAL; @@ -756,7 +762,7 @@ error = VOP_READLINK(vp, uiop, cred); getret = VOP_GETATTR(vp, &attr, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED); @@ -781,9 +787,9 @@ m_freem(mp3); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -819,6 +825,7 @@ struct nfsheur *nh; off_t off; int ioflag = 0; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -857,19 +864,18 @@ error = (vp->v_type == VDIR) ? EISDIR : EACCES; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); if (!error) { - if ((error = nfsrv_access_withgiant(vp, VREAD, cred, rdonly, - td, 1)) != 0) - error = nfsrv_access_withgiant(vp, VEXEC, cred, - rdonly, td, 1); + if ((error = nfsrv_access(vp, VREAD, cred, rdonly, td, 1)) + != 0) + error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 1); } getret = VOP_GETATTR(vp, vap, cred, td); if (!error) error = getret; if (error) { vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3)); @@ -878,7 +884,7 @@ error = 0; goto nfsmout; } - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); /* @@ -1005,7 +1011,7 @@ uiop->uio_resid = len; uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred); off = uiop->uio_offset; nh->nh_nextr = off; @@ -1015,7 +1021,7 @@ error = getret; m_freem(mreq); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3)); @@ -1026,11 +1032,11 @@ } } else { uiop->uio_resid = 0; - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); } - mtx_assert(&Giant, MA_OWNED); /* VFS */ + VFS_ASSERT_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_srvfillattr(vap, fp); @@ -1051,9 +1057,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -1090,6 +1096,7 @@ struct uio io, *uiop = &io; off_t off; struct mount *mntp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1106,10 +1113,10 @@ goto ereply; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mntp); (void) vn_start_write(NULL, &mntp, V_WAIT); vfs_rel(mntp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); if (v3) { tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED); @@ -1175,9 +1182,9 @@ } if (v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); forat_ret = VOP_GETATTR(vp, &forat, cred, td); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } if (vp->v_type != VREG) { @@ -1187,12 +1194,13 @@ error = (vp->v_type == VDIR) ? EISDIR : EACCES; } if (!error) - error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); + error = nfsrv_access_locked(vp, VWRITE, cred, rdonly, td, + 1); if (error) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_WCCDATA(v3)); @@ -1236,17 +1244,17 @@ uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = NULL; uiop->uio_offset = off; - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VOP_WRITE(vp, uiop, ioflags, cred); /* XXXRW: unlocked write. */ nfsrvstats.srvvop_writes++; FREE((caddr_t)iv, M_TEMP); } else - mtx_lock(&Giant); /* VFS */ - mtx_assert(&Giant, MA_OWNED); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + VFS_ASSERT_GIANT(vp->v_mount); aftat_ret = VOP_GETATTR(vp, vap, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; if (!error) @@ -1288,11 +1296,11 @@ nfsmout: NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mntp); if (vp) vput(vp); vn_finished_write(mntp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); return(error); } @@ -1348,6 +1356,7 @@ struct uio io, *uiop = &io; u_quad_t cur_usec; struct mount *mntp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1507,9 +1516,9 @@ if (!error) { if (v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); forat_ret = VOP_GETATTR(vp, &forat, cred, td); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } if (vp->v_type != VREG) { @@ -1522,10 +1531,9 @@ vp = NULL; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); if (!error) - error = nfsrv_access_withgiant(vp, VWRITE, cred, rdonly, - td, 1); + error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE) ioflags = IO_NODELOCKED; else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC) @@ -1579,7 +1587,7 @@ vput(vp); vp = NULL; } - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); /* @@ -1742,6 +1750,7 @@ u_quad_t tempsize; u_char cverf[NFSX_V3CREATEVERF]; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1758,10 +1767,10 @@ goto ereply_locked; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); @@ -1782,9 +1791,9 @@ &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); if (dirp && !v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(dirp->v_mount); vrele(dirp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); dirp = NULL; } @@ -1859,6 +1868,10 @@ * * The only possible error we can have at this point is EEXIST. * nd.ni_vp will also be non-NULL in that case. + * + * XXXRW: For now acquire Giant unconditionally during create to + * avoid interactions between Giant for ndvp and Giant for vp if it + * already exists. */ NFSD_UNLOCK(); mtx_lock(&Giant); /* VFS */ @@ -1938,8 +1951,8 @@ } } else { if (vap->va_size != -1) { - error = nfsrv_access_withgiant(nd.ni_vp, VWRITE, - cred, (nd.ni_cnd.cn_flags & RDONLY), td, 0); + error = nfsrv_access(nd.ni_vp, VWRITE, cred, + (nd.ni_cnd.cn_flags & RDONLY), td, 0); if (!error) { tempsize = vap->va_size; VATTR_NULL(vap); @@ -2052,6 +2065,7 @@ fhandle_t *fhp; struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2067,10 +2081,10 @@ goto ereply; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); @@ -2092,6 +2106,11 @@ error = 0; goto nfsmout; } + + /* + * XXXRW: For now, acquire Giant unconditionally to avoid complexity + * of dealing with Giant separately for dvp and vp. + */ tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED); vtyp = nfsv3tov_type(*tl); if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) { @@ -2212,9 +2231,9 @@ nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft); } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); vn_finished_write(mp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); return (0); nfsmout: @@ -2261,6 +2280,7 @@ nfsfh_t nfh; fhandle_t *fhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2274,10 +2294,10 @@ goto ereply; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); @@ -2386,6 +2406,7 @@ fhandle_t *ffhp, *tfhp; uid_t saved_uid; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2409,10 +2430,10 @@ goto out1; } NFSD_UNLOCK(); - mtx_lock(&Giant); + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); /* @@ -2427,9 +2448,9 @@ &dpos, &fdirp, v3, &fdirfor, &fdirfor_ret, td, FALSE); if (fdirp && !v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(fdirp->v_mount); vrele(fdirp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); fdirp = NULL; } @@ -2639,6 +2660,7 @@ nfsfh_t nfh, dnfh; fhandle_t *fhp, *dfhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2653,10 +2675,10 @@ goto ereply; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvmtofh(dfhp); nfsm_srvnamesiz(len); @@ -2803,12 +2825,18 @@ nfsfh_t nfh; fhandle_t *fhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); + /* + * XXXRW: For now, unconditionally acquire Giant in several places to + * avoid complexity of unwinding separately when several vnodes are + * in flight. + */ fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { @@ -2818,10 +2846,10 @@ goto out; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -2998,12 +3026,17 @@ nfsfh_t nfh; fhandle_t *fhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); ndclear(&nd); + /* + * XXXRW: For now, unconditionally acquire Giant so as to avoid the + * complexity of tracking it for several in-flight vnodes. + */ fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { @@ -3013,10 +3046,10 @@ goto out; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -3027,9 +3060,9 @@ &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); if (dirp && !v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(dirp->v_mount); vrele(dirp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); dirp = NULL; } @@ -3174,6 +3207,7 @@ fhandle_t *fhp; struct nameidata nd; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -3187,10 +3221,10 @@ goto out; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); nfsm_srvnamesiz(len); nd.ni_cnd.cn_cred = cred; @@ -3200,9 +3234,9 @@ &dirp, v3, &dirfor, &dirfor_ret, td, FALSE); if (dirp && !v3) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(dirp->v_mount); vrele(dirp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); dirp = NULL; } @@ -3234,6 +3268,9 @@ /* * Issue or abort op. Since SAVESTART is not set, path name * component is freed by the VOP after either. + * + * XXXRW: For now, acquire Giant unconditionally to avoid the + * complexity of unwinding Giant for several vnodes in flight. */ NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); @@ -3357,6 +3394,7 @@ int v3 = (nfsd->nd_flag & ND_NFSV3); u_quad_t off, toff, verf; u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ + int vfslocked; NFSD_LOCK_ASSERT(); @@ -3387,9 +3425,9 @@ if (!error && vp->v_type != VDIR) { error = ENOTDIR; NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; } @@ -3405,7 +3443,7 @@ * Obtain lock on vnode for this section of the code */ NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); if (v3) { error = getret = VOP_GETATTR(vp, &at, cred, td); #if 0 @@ -3417,10 +3455,10 @@ #endif } if (!error) - error = nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0); + error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); if (error) { vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_POSTOPATTR(v3)); @@ -3464,7 +3502,7 @@ VOP_UNLOCK(vp, 0, td); if (error) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; free((caddr_t)rbuf, M_TEMP); if (cookies) @@ -3485,7 +3523,7 @@ */ if (siz == 0) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + @@ -3535,7 +3573,7 @@ goto again; } - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */ nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz); @@ -3614,9 +3652,9 @@ ncookies--; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_clget; @@ -3640,9 +3678,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -3677,6 +3715,7 @@ u_quad_t off, toff, verf; u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */ int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -3704,9 +3743,9 @@ if (!error && vp->v_type != VDIR) { error = ENOTDIR; NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); } @@ -3717,7 +3756,7 @@ goto nfsmout; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = getret = VOP_GETATTR(vp, &at, cred, td); #if 0 /* @@ -3727,10 +3766,10 @@ error = NFSERR_BAD_COOKIE; #endif if (!error) - error = nfsrv_access_withgiant(vp, VEXEC, cred, rdonly, td, 0); + error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0); if (error) { vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR); @@ -3767,7 +3806,7 @@ error = getret; if (error) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; if (cookies) free((caddr_t)cookies, M_TEMP); @@ -3787,7 +3826,7 @@ */ if (siz == 0) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + @@ -3842,7 +3881,7 @@ EOPNOTSUPP) { error = NFSERR_NOTSUPP; vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; free((caddr_t)cookies, M_TEMP); free((caddr_t)rbuf, M_TEMP); @@ -3853,7 +3892,7 @@ goto nfsmout; } vput(nvp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); nvp = NULL; dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + @@ -3868,7 +3907,7 @@ be = bp + M_TRAILINGSPACE(mp); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + VFS_LOCK_GIANT(vp->v_mount); /* Loop through the records and build reply */ while (cpos < cend && ncookies > 0) { if (dp->d_fileno != 0 && dp->d_type != DT_WHT) { @@ -3885,6 +3924,13 @@ bzero((caddr_t)nfhp, NFSX_V3FH); nfhp->fh_fsid = nvp->v_mount->mnt_stat.f_fsid; + /* + * XXXRW: Assert the mountpoints are the same so that + * we know that acquiring Giant based on the + * directory is the right thing for the child. + */ + KASSERT(nvp->v_mount == vp->v_mount, + ("nfsrv_readdirplus: nvp mount != vp mount")); if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) { vput(nvp); nvp = NULL; @@ -3982,7 +4028,7 @@ ncookies--; } vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; nfsm_clget_nolock; *tl = nfsrv_nfs_false; @@ -4005,9 +4051,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -4035,6 +4081,7 @@ u_quad_t off; struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -4048,10 +4095,10 @@ goto ereply; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); (void) vn_start_write(NULL, &mp, V_WAIT); vfs_rel(mp); /* The write holds a ref. */ - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED); @@ -4070,7 +4117,7 @@ goto nfsmout; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); for_ret = VOP_GETATTR(vp, &bfor, cred, td); if (cnt > MAX_COMMIT_COUNT) { @@ -4158,7 +4205,7 @@ aft_ret = VOP_GETATTR(vp, &aft, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); ereply: @@ -4177,11 +4224,11 @@ nfsmout: NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(mp); if (vp) vput(vp); vn_finished_write(mp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); return(error); } @@ -4209,6 +4256,7 @@ fhandle_t *fhp; struct statfs statfs; u_quad_t tval; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -4225,11 +4273,11 @@ } sf = &statfs; NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VFS_STATFS(vp->v_mount, sf, td); getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3)); @@ -4280,9 +4328,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -4310,6 +4358,7 @@ u_quad_t maxfsize; struct statfs sb; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -4327,14 +4376,14 @@ } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); /* XXX Try to make a guess on the max file size. */ VFS_STATFS(vp->v_mount, &sb, td); maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1; getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO); @@ -4367,9 +4416,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -4396,6 +4445,7 @@ nfsfh_t nfh; fhandle_t *fhp; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -4412,7 +4462,7 @@ goto nfsmout; } NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax); if (!error) error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax); @@ -4422,7 +4472,7 @@ error = VOP_PATHCONF(vp, _PC_NO_TRUNC, ¬runc); getret = VOP_GETATTR(vp, &at, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF); @@ -4449,9 +4499,9 @@ NFSD_LOCK_ASSERT(); if (vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); } return(error); @@ -4521,19 +4571,24 @@ * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS() * will return EPERM instead of EACCESS. EPERM is always an error. * - * There are two versions: one to be called while holding Giant (which is - * needed due to use of VFS), and the other called with the NFS server lock - * (which will be dropped and reacquired). This is necessary because - * nfsrv_access checks are required from both classes of contexts. + * There are two versions: one called while holding the NFS server lock, + * which will be dropped and re-acquired, and one called without it. + * + * nfsrv_access() assumes that the NFS server lock is not held, but that if + * Giant is required for the vnode it will already be acquired. + * + * nfsrv_access_locked() assumes that the NFS server lock is held, but that + * it will need to acquire Giant for the vnode. */ static int -nfsrv_access_withgiant(struct vnode *vp, int flags, struct ucred *cred, +nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, struct thread *td, int override) { struct vattr vattr; int error; - GIANT_REQUIRED; + NFSD_UNLOCK_ASSERT(); + VFS_ASSERT_GIANT(vp->v_mount); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); @@ -4576,17 +4631,17 @@ } static int -nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, - struct thread *td, int override) +nfsrv_access_locked(struct vnode *vp, int flags, struct ucred *cred, + int rdonly, struct thread *td, int override) { - int error; + int error, vfslocked; NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ - error = nfsrv_access_withgiant(vp, flags, cred, rdonly, td, override); - mtx_unlock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + error = nfsrv_access(vp, flags, cred, rdonly, td, override); + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); return (error); }