summaryrefslogtreecommitdiffstats
path: root/sys/nfsserver/nfs_serv.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2006-11-24 11:53:16 +0000
committerrwatson <rwatson@FreeBSD.org>2006-11-24 11:53:16 +0000
commit65d3526a649a6b8c43d95db3632ccd500d0435e7 (patch)
treee361363025d1a88f47fe0ef4f20658e774c2ac7d /sys/nfsserver/nfs_serv.c
parent3caf2aa43d126fdf7524e1e18b68a6859dcbbf41 (diff)
downloadFreeBSD-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/nfsserver/nfs_serv.c')
-rw-r--r--sys/nfsserver/nfs_serv.c476
1 files changed, 263 insertions, 213 deletions
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, &notrunc);
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);
-}
OpenPOWER on IntegriCloud