diff options
author | rwatson <rwatson@FreeBSD.org> | 2006-11-24 11:53:16 +0000 |
---|---|---|
committer | rwatson <rwatson@FreeBSD.org> | 2006-11-24 11:53:16 +0000 |
commit | 65d3526a649a6b8c43d95db3632ccd500d0435e7 (patch) | |
tree | e361363025d1a88f47fe0ef4f20658e774c2ac7d /sys | |
parent | 3caf2aa43d126fdf7524e1e18b68a6859dcbbf41 (diff) | |
download | FreeBSD-src-65d3526a649a6b8c43d95db3632ccd500d0435e7.zip FreeBSD-src-65d3526a649a6b8c43d95db3632ccd500d0435e7.tar.gz |
Push Giant a bit further off the NFS server in a number of straight
forward cases by converting from unconditional acquisition of Giant
around vnode operations to conditional acquisition:
- Remove nfsrv_access_withgiant(), and cause nfsrv_access() to now
assert that Giant will be held if it is required for the vnode.
- Add nfsrv_fhtovp_locked(), which will drop the NFS server lock if
required, and modify nfsrv_fhtovp() to conditionally acquire
Giant if required.
- In the VOP's not dealing with more than one vnode at a time (i.e.,
not involving a lookup), conditionally acquire Giant.
This removes Giant use for MPSAFE file systems for a number of quite
important RPCs, including getattr, read, write. It leaves
unconditional Giant acquisitions in vnode operations that interact
with the name space or more than one vnode at a time as these
require further work.
Tested by: kris
Reviewed by: kib
Diffstat (limited to 'sys')
-rw-r--r-- | sys/nfsserver/nfs.h | 3 | ||||
-rw-r--r-- | sys/nfsserver/nfs_serv.c | 476 | ||||
-rw-r--r-- | sys/nfsserver/nfs_srvsubs.c | 42 |
3 files changed, 297 insertions, 224 deletions
diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h index c3b231a..292584e 100644 --- a/sys/nfsserver/nfs.h +++ b/sys/nfsserver/nfs.h @@ -360,6 +360,9 @@ int nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct thread *td, struct mbuf **mrq); int nfsrv_fhtovp(fhandle_t *, int, struct vnode **, struct ucred *, struct nfssvc_sock *, struct sockaddr *, int *, int); +int nfsrv_fhtovp_locked(fhandle_t *, int, struct vnode **, + struct ucred *, struct nfssvc_sock *, struct sockaddr *, int *, + int); int nfsrv_setpublicfs(struct mount *, struct netexport *, struct export_args *); int nfs_ispublicfh(fhandle_t *); diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c index c193bf6..0e54d8a 100644 --- a/sys/nfsserver/nfs_serv.c +++ b/sys/nfsserver/nfs_serv.c @@ -137,11 +137,8 @@ struct nfsrvstats nfsrvstats; 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 void nfsrvw_coalesce(struct nfsrv_descript *, struct nfsrv_descript *); @@ -181,6 +178,7 @@ nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct vattr vattr, *vap = &vattr; u_long testmode, nfsmode; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -190,18 +188,20 @@ nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED); - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); + NFSD_UNLOCK(); + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(1, NULL); error = 0; goto nfsmout; } 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 @@ nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 @@ nfsmout: 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,23 +259,25 @@ nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, caddr_t bpos; int error = 0, rdonly; struct mbuf *mb, *mreq; + int vfslocked; NFSD_LOCK_ASSERT(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(0); error = 0; 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 +294,9 @@ nfsmout: 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,23 +327,24 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct mbuf *mb, *mreq; struct timespec guard; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); VATTR_NULL(vap); + NFSD_LOCK(); if (v3) { nfsm_srvsattr(vap); tl = nfsm_dissect_nonblock(u_int32_t *, NFSX_UNSIGNED); @@ -380,12 +383,14 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime); } + NFSD_UNLOCK(); /* * Now that we have all the fields, lets do it. */ error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); if (v3) nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); @@ -397,8 +402,7 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * vp now an active resource, pay careful attention to cleanup */ 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 +410,7 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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,10 +419,8 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = 0; goto nfsmout; } - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); } - NFSD_LOCK_ASSERT(); /* * If the size is being changed write acces is required, otherwise @@ -434,28 +436,25 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = EISDIR; goto out; } else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly, - td, 0)) != 0) + 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); if (!error) error = postat_ret; out: - NFSD_LOCK_ASSERT(); + NFSD_UNLOCK_ASSERT(); if (vp != NULL) { - NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); } vp = NULL; + NFSD_LOCK(); nfsm_reply(NFSX_WCCORFATTR(v3)); if (v3) { nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap); @@ -470,11 +469,11 @@ out: 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); } @@ -517,13 +516,16 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART; error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos, &dirp, v3, &dirattr, &dirattr_ret, td, pubflag); + NFSD_UNLOCK(); /* * 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) { if (dirp) { @@ -696,6 +698,7 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsfh_t nfh; fhandle_t *fhp; struct uio io, *uiop = &io; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -706,9 +709,9 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, mp3 = NULL; fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); len = 0; i = 0; - NFSD_UNLOCK(); while (len < NFS_MAXPATHLEN) { MGET(nmp, M_TRYWAIT, MT_DATA); MCLGET(nmp, M_TRYWAIT); @@ -736,17 +739,16 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, uiop->uio_rw = UIO_READ; uiop->uio_segflg = UIO_SYSSPACE; uiop->uio_td = NULL; - NFSD_LOCK(); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); if (v3) nfsm_srvpostop_attr(1, NULL); error = 0; 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 +758,7 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 +783,9 @@ nfsmout: 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 +821,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct nfsheur *nh; off_t off; int ioflag = 0; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -833,16 +836,18 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, off = (off_t)fxdr_unsigned(u_int32_t, *tl); } nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd)); + NFSD_UNLOCK(); /* * Reference vp. If an error occurs, vp will be invalid, but we * have to NULL it just in case. The macros might goto nfsmout * as well. */ - - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + TRUE); if (error) { vp = NULL; + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); if (v3) nfsm_srvpostop_attr(1, NULL); @@ -856,20 +861,18 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, else 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,8 +881,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = 0; goto nfsmout; } - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); /* * Calculate byte count to read @@ -892,6 +894,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, else cnt = reqlen; + NFSD_LOCK(); /* * Calculate seqcount for heuristic */ @@ -958,8 +961,8 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fp = (struct nfs_fattr *)tl; tl += (NFSX_V2FATTR / sizeof (u_int32_t)); } - len = left = nfsm_rndup(cnt); NFSD_UNLOCK(); + len = left = nfsm_rndup(cnt); if (cnt > 0) { /* * Generate the mbuf list with the uio_iov ref. to it. @@ -1005,7 +1008,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 +1018,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 +1029,11 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } } 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 +1054,9 @@ nfsmout: 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 +1093,7 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, struct uio io, *uiop = &io; off_t off; struct mount *mntp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1101,23 +1105,27 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); if ((mntp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; + NFSD_LOCK(); 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); if (v3) { + NFSD_LOCK(); tl = nfsm_dissect_nonblock(u_int32_t *, 5 * NFSX_UNSIGNED); + NFSD_UNLOCK(); off = fxdr_hyper(tl); tl += 3; stable = fxdr_unsigned(int, *tl++); } else { + NFSD_LOCK(); tl = nfsm_dissect_nonblock(u_int32_t *, 4 * NFSX_UNSIGNED); + NFSD_UNLOCK(); off = (off_t)fxdr_unsigned(u_int32_t, *++tl); tl += 2; if (nfs_async) @@ -1158,15 +1166,18 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } if (len > NFS_MAXDATA || len < 0 || i < len) { error = EIO; + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); if (v3) nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); error = 0; goto nfsmout; } - error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); + error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, + TRUE); if (error) { vp = NULL; + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); if (v3) nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); @@ -1174,11 +1185,9 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto nfsmout; } 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); } if (vp->v_type != VREG) { if (v3) @@ -1186,15 +1195,17 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, else error = (vp->v_type == VDIR) ? EISDIR : EACCES; } - if (!error) + if (!error) { + vfslocked = VFS_LOCK_GIANT(vp->v_mount); error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1); + VFS_UNLOCK_GIANT(vfslocked); + } if (error) { - NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ + vfslocked = VFS_LOCK_GIANT(vp->v_mount); vput(vp); - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; + NFSD_LOCK(); nfsm_reply(NFSX_WCCDATA(v3)); if (v3) nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap); @@ -1202,7 +1213,6 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto nfsmout; } - NFSD_UNLOCK(); if (len > 0) { MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP, M_WAITOK); @@ -1236,21 +1246,21 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; if (!error) error = aftat_ret; + NFSD_LOCK(); ereply: NFSD_LOCK_ASSERT(); nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) + @@ -1288,11 +1298,11 @@ ereply: 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); } @@ -1308,6 +1318,8 @@ nfsrv_samecred(struct ucred *cr1, struct ucred *cr2) { int i; + NFSD_LOCK_DONTCARE(); + if (cr1->cr_uid != cr2->cr_uid) return (0); if (cr1->cr_ngroups != cr2->cr_ngroups) @@ -1348,6 +1360,7 @@ nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp, struct uio io, *uiop = &io; u_quad_t cur_usec; struct mount *mntp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1501,16 +1514,15 @@ loop1: nfsd->nd_mrep = NULL; cred = nfsd->nd_cr; v3 = (nfsd->nd_flag & ND_NFSV3); + NFSD_UNLOCK(); forat_ret = aftat_ret = 1; error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp, nfsd->nd_nam, &rdonly, TRUE); 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); } if (vp->v_type != VREG) { if (v3) @@ -1521,11 +1533,9 @@ loop1: } else { 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,13 +1589,13 @@ loop1: vput(vp); vp = NULL; } - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); /* * Loop around generating replies for all write rpcs that have * now been completed. */ + NFSD_LOCK(); swp = nfsd; do { NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff)); @@ -1648,6 +1658,7 @@ loop1: * Search for a reply to return. */ s = splsoftclock(); + NFSD_LOCK_ASSERT(); LIST_FOREACH(nfsd, &slp->ns_tq, nd_tq) if (nfsd->nd_mreq) { NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff)); @@ -1742,6 +1753,7 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, u_quad_t tempsize; u_char cverf[NFSX_V3CREATEVERF]; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -1753,15 +1765,16 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; + NFSD_LOCK(); 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 +1795,9 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, &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; } @@ -1829,10 +1842,12 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, exclusive_flag = 1; break; }; + NFSD_UNLOCK(); vap->va_type = VREG; } else { sp = nfsm_dissect_nonblock(struct nfsv2_sattr *, NFSX_V2SATTR); vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode)); + NFSD_UNLOCK(); if (vap->va_type == VNON) vap->va_type = VREG; vap->va_mode = nfstov_mode(sp->sa_mode); @@ -1859,8 +1874,11 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * * 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 */ if (nd.ni_vp == NULL) { if (vap->va_mode == (mode_t)VNOVAL) @@ -1938,8 +1956,8 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, } } 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 +2070,7 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhandle_t *fhp; struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2062,15 +2081,16 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; + NFSD_LOCK(); 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,12 +2112,17 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ error = NFSERR_BADTYPE; + mtx_lock(&Giant); /* VFS */ goto out; } VATTR_NULL(vap); @@ -2114,8 +2139,8 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, */ if (nd.ni_vp) { NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ error = EEXIST; + mtx_lock(&Giant); /* VFS */ goto out; } vap->va_type = vtyp; @@ -2168,6 +2193,7 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, * send response, cleanup, return. */ out: + GIANT_REQUIRED; NFSD_UNLOCK_ASSERT(); vp = nd.ni_vp; if (!error) { @@ -2212,9 +2238,9 @@ ereply: 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 +2287,7 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsfh_t nfh; fhandle_t *fhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2269,15 +2296,16 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); + NFSD_UNLOCK(); if ((mp = vfs_getvfs(&fhp->fh_fsid)) == NULL) { error = ESTALE; + NFSD_LOCK(); 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 +2414,7 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhandle_t *ffhp, *tfhp; uid_t saved_uid; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2404,15 +2433,16 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, ndclear(&tond); nfsm_srvmtofh(ffhp); + NFSD_UNLOCK(); if ((mp = vfs_getvfs(&ffhp->fh_fsid)) == NULL) { error = ESTALE; + NFSD_LOCK(); 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 +2457,9 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, &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; } @@ -2518,6 +2548,7 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fromnd.ni_cnd.cn_namelen)) error = -1; out: + GIANT_REQUIRED; NFSD_UNLOCK_ASSERT(); if (!error) { /* @@ -2639,6 +2670,7 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsfh_t nfh, dnfh; fhandle_t *fhp, *dfhp; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -2653,15 +2685,16 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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); - error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, slp, nam, &rdonly, TRUE); + error = nfsrv_fhtovp_locked(fhp, TRUE, &vp, cred, slp, nam, &rdonly, + TRUE); if (error) { nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3)); if (v3) { @@ -2803,12 +2836,18 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 +2857,10 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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; @@ -2999,12 +3038,17 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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) { @@ -3014,10 +3058,10 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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; @@ -3028,9 +3072,9 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, &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; } @@ -3175,6 +3219,7 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhandle_t *fhp; struct nameidata nd; struct mount *mp = NULL; + int vfslocked; NFSD_LOCK_ASSERT(); @@ -3188,10 +3233,10 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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; @@ -3201,9 +3246,9 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, &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; } @@ -3235,6 +3280,9 @@ out: /* * 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(); @@ -3358,6 +3406,7 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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(); @@ -3375,6 +3424,7 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, toff = fxdr_unsigned(u_quad_t, *tl++); verf = 0; /* shut up gcc */ } + NFSD_UNLOCK(); off = toff; cnt = fxdr_unsigned(int, *tl); siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); @@ -3387,14 +3437,13 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; } if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); if (v3) nfsm_srvpostop_attr(getret, &at); @@ -3405,8 +3454,7 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, /* * 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 @@ -3418,10 +3466,10 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, #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)); @@ -3465,7 +3513,7 @@ again: 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) @@ -3486,7 +3534,7 @@ again: */ 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) + @@ -3536,7 +3584,7 @@ again: 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); @@ -3615,9 +3663,9 @@ again: 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; @@ -3641,9 +3689,9 @@ nfsmout: 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); @@ -3678,6 +3726,7 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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(); @@ -3696,6 +3745,7 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, off = toff; siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1)); xfer = NFS_SRVMAXDATA(nfsd); + NFSD_UNLOCK(); if (cnt > xfer) cnt = xfer; if (siz > xfer) @@ -3704,21 +3754,19 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); 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(); } if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); error = 0; 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 /* @@ -3728,10 +3776,10 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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); @@ -3768,7 +3816,7 @@ again: error = getret; if (error) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; if (cookies) free((caddr_t)cookies, M_TEMP); @@ -3788,7 +3836,7 @@ again: */ if (siz == 0) { vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); NFSD_LOCK(); vp = NULL; nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + @@ -3843,7 +3891,7 @@ again: 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); @@ -3854,7 +3902,7 @@ again: goto nfsmout; } vput(nvp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); nvp = NULL; dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + @@ -3869,7 +3917,7 @@ again: 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) { @@ -3886,6 +3934,13 @@ again: 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; @@ -3983,7 +4038,7 @@ invalid: ncookies--; } vrele(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; nfsm_clget_nolock; *tl = nfsrv_nfs_false; @@ -4006,9 +4061,9 @@ nfsmout: 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); @@ -4036,6 +4091,7 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, u_quad_t off; struct mount *mp = NULL; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); @@ -4049,11 +4105,10 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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 */ - NFSD_LOCK(); + VFS_UNLOCK_GIANT(vfslocked); tl = nfsm_dissect_nonblock(u_int32_t *, 3 * NFSX_UNSIGNED); /* @@ -4065,13 +4120,13 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, cnt = fxdr_unsigned(int, *tl); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(2 * NFSX_UNSIGNED); nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft); error = 0; 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) { @@ -4159,7 +4214,7 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, aft_ret = VOP_GETATTR(vp, &aft, cred, td); vput(vp); - mtx_unlock(&Giant); /* VFS */ + VFS_UNLOCK_GIANT(vfslocked); vp = NULL; NFSD_LOCK(); ereply: @@ -4178,11 +4233,11 @@ ereply: 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); } @@ -4210,14 +4265,17 @@ nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, fhandle_t *fhp; struct statfs statfs; u_quad_t tval; + int vfslocked; NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); fhp = &nfh.fh_generic; nfsm_srvmtofh(fhp); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); if (v3) nfsm_srvpostop_attr(getret, &at); @@ -4225,12 +4283,11 @@ nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, goto nfsmout; } 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)); @@ -4281,9 +4338,9 @@ nfsmout: 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); @@ -4311,8 +4368,10 @@ nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, u_quad_t maxfsize; struct statfs sb; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) @@ -4321,21 +4380,21 @@ nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsm_srvmtofh(fhp); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); error = 0; goto nfsmout; } - 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); @@ -4368,9 +4427,9 @@ nfsmout: 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); @@ -4397,8 +4456,10 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsfh_t nfh; fhandle_t *fhp; int v3 = (nfsd->nd_flag & ND_NFSV3); + int vfslocked; NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); nfsdbprintf(("%s %d\n", __FILE__, __LINE__)); if (!v3) @@ -4407,13 +4468,13 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, nfsm_srvmtofh(fhp); error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly, TRUE); if (error) { + NFSD_LOCK(); nfsm_reply(NFSX_UNSIGNED); nfsm_srvpostop_attr(getret, &at); error = 0; 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); @@ -4423,7 +4484,7 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp, 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); @@ -4450,9 +4511,9 @@ nfsmout: 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); @@ -4522,19 +4583,24 @@ nfsmout: * 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__)); @@ -4575,19 +4641,3 @@ nfsrv_access_withgiant(struct vnode *vp, int flags, struct ucred *cred, error = 0; return (error); } - -static int -nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly, - struct thread *td, int override) -{ - int error; - - NFSD_LOCK_ASSERT(); - - NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ - error = nfsrv_access_withgiant(vp, flags, cred, rdonly, td, override); - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); - return (error); -} diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c index a6bcb8ea..e2238f1 100644 --- a/sys/nfsserver/nfs_srvsubs.c +++ b/sys/nfsserver/nfs_srvsubs.c @@ -624,7 +624,6 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, NFSD_LOCK_ASSERT(); NFSD_UNLOCK(); - mtx_lock(&Giant); /* VFS */ *retdirp = NULL; cnp->cn_flags |= NOMACCHECK; @@ -643,14 +642,14 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, md = md->m_next; if (md == NULL) { error = EBADRPC; - goto out; + goto out_nogiant; } fromcp = mtod(md, caddr_t); rem = md->m_len; } if (*fromcp == '\0' || (!pubflag && *fromcp == '/')) { error = EACCES; - goto out; + goto out_nogiant; } *tocp++ = *fromcp++; rem--; @@ -663,17 +662,17 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, if (rem >= len) *dposp += len; else if ((error = nfs_adv(mdp, dposp, len, rem)) != 0) - goto out; + goto out_nogiant; } /* * Extract and set starting directory. + * + * XXXRW: For now, acquire Giant unconditionally to avoid tracking it + * on multiple vnodes. */ - mtx_unlock(&Giant); /* VFS */ - NFSD_LOCK(); error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, nam, &rdonly, pubflag); - NFSD_UNLOCK(); mtx_lock(&Giant); /* VFS */ if (error) goto out; @@ -889,6 +888,8 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len, * cleanup state trivially. */ out: + mtx_unlock(&Giant); /* VFS */ +out_nogiant: if (error) { uma_zfree(namei_zone, cnp->cn_pnbuf); ndp->ni_vp = NULL; @@ -898,7 +899,6 @@ out: } else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) { ndp->ni_dvp = NULL; } - mtx_unlock(&Giant); /* VFS */ NFSD_LOCK(); return (error); } @@ -1064,6 +1064,10 @@ nfsm_srvfattr(struct nfsrv_descript *nfsd, struct vattr *vap, * - get vp and export rights by calling VFS_FHTOVP() * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon * - if not lockflag unlock it with VOP_UNLOCK() + * + * As this routine may acquire Giant and may sleep, it can't be called with + * nfsd_mtx. Caller should invoke nfsrv_fhtovp_locked() if the lock is held + * so that it can be automatically dropped and re-acquired. */ int nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, @@ -1080,7 +1084,7 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, struct sockaddr_int *saddr; #endif - NFSD_LOCK_ASSERT(); + NFSD_UNLOCK_ASSERT(); *vpp = NULL; @@ -1093,7 +1097,6 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, mp = vfs_getvfs(&fhp->fh_fsid); if (!mp) return (ESTALE); - NFSD_UNLOCK(); vfslocked = VFS_LOCK_GIANT(mp); error = VFS_CHECKEXP(mp, nam, &exflags, &credanon); if (error) @@ -1133,10 +1136,27 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp, out: vfs_rel(mp); VFS_UNLOCK_GIANT(vfslocked); - NFSD_LOCK(); return (error); } +/* + * Version of nfsrv_fhtovp() that can be called holding nfsd_mtx: it will + * drop and re-acquire the lock for the caller. + */ +int +nfsrv_fhtovp_locked(fhandle_t *fhp, int lockflag, struct vnode **vpp, + struct ucred *cred, struct nfssvc_sock *slp, struct sockaddr *nam, + int *rdonlyp, int pubflag) +{ + int error; + + NFSD_LOCK_ASSERT(); + NFSD_UNLOCK(); + error = nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp, + pubflag); + NFSD_LOCK(); + return (error); +} /* * WebNFS: check if a filehandle is a public filehandle. For v3, this |