summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/nfsserver/nfs.h11
-rw-r--r--sys/nfsserver/nfs_serv.c432
-rw-r--r--sys/nfsserver/nfs_srvcache.c26
-rw-r--r--sys/nfsserver/nfs_srvsock.c52
-rw-r--r--sys/nfsserver/nfs_srvsubs.c133
-rw-r--r--sys/nfsserver/nfs_syscalls.c65
-rw-r--r--sys/nfsserver/nfsm_subs.h7
7 files changed, 642 insertions, 84 deletions
diff --git a/sys/nfsserver/nfs.h b/sys/nfsserver/nfs.h
index 5295b69..3f83115 100644
--- a/sys/nfsserver/nfs.h
+++ b/sys/nfsserver/nfs.h
@@ -116,6 +116,13 @@ struct nfsd_args {
#ifdef _KERNEL
+extern struct mtx nfsd_mtx;
+#define NFSD_LOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_OWNED)
+#define NFSD_UNLOCK_ASSERT() mtx_assert(&nfsd_mtx, MA_NOTOWNED)
+#define NFSD_LOCK_DONTCARE()
+#define NFSD_LOCK() mtx_lock(&nfsd_mtx)
+#define NFSD_UNLOCK() mtx_unlock(&nfsd_mtx)
+
#ifdef MALLOC_DECLARE
MALLOC_DECLARE(M_NFSRVDESC);
MALLOC_DECLARE(M_NFSD);
@@ -145,8 +152,8 @@ extern u_int32_t nfsrv_rpc_auth_unix, nfsrv_rpc_msgaccepted, nfsrv_rpc_call,
nfsrv_rpc_autherr;
/* Procedure table data */
-extern int nfsrvv2_procid[NFS_NPROCS];
-extern int nfsrv_nfsv3_procid[NFS_NPROCS];
+extern const int nfsrvv2_procid[NFS_NPROCS];
+extern const int nfsrv_nfsv3_procid[NFS_NPROCS];
extern int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
struct nfssvc_sock *slp, struct thread *td,
struct mbuf **mreqp);
diff --git a/sys/nfsserver/nfs_serv.c b/sys/nfsserver/nfs_serv.c
index 258da54..ea06231 100644
--- a/sys/nfsserver/nfs_serv.c
+++ b/sys/nfsserver/nfs_serv.c
@@ -179,6 +179,8 @@ nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
u_long testmode, nfsmode;
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv3_access: v3 proc called on a v2 connection");
@@ -211,9 +213,13 @@ nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
if ((nfsmode & testmode) &&
nfsrv_access(vp, VEXEC, cred, rdonly, td, 0))
nfsmode &= ~testmode;
+ NFSD_UNLOCK();
+ mtx_lock(&Giant);
getret = VOP_GETATTR(vp, vap, cred, td);
vput(vp);
+ mtx_unlock(&Giant);
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
nfsm_srvpostop_attr(getret, vap);
tl = nfsm_build(u_int32_t *, NFSX_UNSIGNED);
@@ -245,6 +251,8 @@ nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
int error = 0, rdonly;
struct mbuf *mb, *mreq;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -254,9 +262,13 @@ nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant);
error = VOP_GETATTR(vp, vap, cred, td);
vput(vp);
+ mtx_unlock(&Giant);
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
if (error) {
error = 0;
@@ -299,6 +311,8 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct timespec guard;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -306,7 +320,11 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto out;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant);
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant);
+ NFSD_LOCK();
VATTR_NULL(vap);
if (v3) {
nfsm_srvsattr(vap);
@@ -363,20 +381,26 @@ 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 */
error = preat_ret = VOP_GETATTR(vp, &preat, cred, td);
if (!error && gcheck &&
(preat.va_ctime.tv_sec != guard.tv_sec ||
preat.va_ctime.tv_nsec != guard.tv_nsec))
error = NFSERR_NOT_SYNC;
if (error) {
+ mtx_unlock(&Giant); /* VFS */
vput(vp);
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_WCCDATA(v3));
if (v3)
nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
error = 0;
goto nfsmout;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
}
/*
@@ -396,13 +420,23 @@ nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
td, 0)) != 0)
goto out;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
error = VOP_SETATTR(vp, vap, cred, td);
postat_ret = VOP_GETATTR(vp, vap, cred, td);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
if (!error)
error = postat_ret;
out:
- if (vp != NULL)
+ if (vp != NULL) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
+
vp = NULL;
nfsm_reply(NFSX_WCCORFATTR(v3));
if (v3) {
@@ -416,9 +450,13 @@ out:
/* fall through */
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant);
if (vp)
vput(vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant);
+ NFSD_LOCK();
return(error);
}
@@ -444,6 +482,8 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct mbuf *mb, *mreq;
struct vattr va, dirattr, *vap = &va;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -464,11 +504,15 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
* structure in case macros jump to nfsmout.
*/
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (error) {
if (dirp) {
vrele(dirp);
dirp = NULL;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
nfsm_srvpostop_attr(dirattr_ret, &dirattr);
@@ -549,6 +593,8 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
*/
if (error) {
+ mtx_unlock(&Giant);
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
nfsm_srvpostop_attr(dirattr_ret, &dirattr);
@@ -577,7 +623,9 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = VOP_GETATTR(vp, vap, cred, td);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
ndp->ni_vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
if (error) {
if (v3)
@@ -595,6 +643,8 @@ nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp)
vrele(dirp);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -602,6 +652,8 @@ nfsmout:
vrele(ndp->ni_startdir);
if (ndp->ni_vp)
vput(ndp->ni_vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -630,6 +682,8 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp;
struct uio io, *uiop = &io;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
mp = NULL;
@@ -639,6 +693,7 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
nfsm_srvmtofh(fhp);
len = 0;
i = 0;
+ NFSD_UNLOCK();
while (len < NFS_MAXPATHLEN) {
MGET(nmp, M_TRYWAIT, MT_DATA);
MCLGET(nmp, M_TRYWAIT);
@@ -666,6 +721,7 @@ 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) {
nfsm_reply(2 * NFSX_UNSIGNED);
@@ -674,18 +730,20 @@ nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (vp->v_type != VLNK) {
if (v3)
error = EINVAL;
else
error = ENXIO;
- goto out;
- }
- error = VOP_READLINK(vp, uiop, cred);
-out:
+ } else
+ error = VOP_READLINK(vp, uiop, cred);
getret = VOP_GETATTR(vp, &attr, cred, td);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
if (v3)
nfsm_srvpostop_attr(getret, &attr);
@@ -705,8 +763,13 @@ out:
nfsmout:
if (mp3)
m_freem(mp3);
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -741,6 +804,8 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
off_t off;
int ioflag = 0;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -779,18 +844,24 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
if ((error = nfsrv_access(vp, VREAD, cred, rdonly, td, 1)) != 0)
error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 1);
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
getret = VOP_GETATTR(vp, vap, cred, td);
if (!error)
error = getret;
if (error) {
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
nfsm_srvpostop_attr(getret, vap);
error = 0;
goto nfsmout;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
/*
* Calculate byte count to read
@@ -870,6 +941,7 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
tl += (NFSX_V2FATTR / sizeof (u_int32_t));
}
len = left = nfsm_rndup(cnt);
+ NFSD_UNLOCK();
if (cnt > 0) {
/*
* Generate the mbuf list with the uio_iov ref. to it.
@@ -915,6 +987,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 */
error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
off = uiop->uio_offset;
nh->nh_nextr = off;
@@ -924,6 +997,8 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = getret;
m_freem(mreq);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
@@ -933,9 +1008,13 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
} else {
uiop->uio_resid = 0;
+ mtx_lock(&Giant); /* VFS */
}
+ mtx_assert(&Giant, MA_OWNED); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
nfsm_srvfillattr(vap, fp);
tlen = len - uiop->uio_resid;
cnt = cnt < tlen ? cnt : tlen;
@@ -951,8 +1030,13 @@ nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
*tl = txdr_unsigned(cnt);
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -988,6 +1072,8 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
off_t off;
struct mount *mntp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (mrep == NULL) {
*mrq = NULL;
@@ -1000,7 +1086,11 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mntp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
if (v3) {
tl = nfsm_dissect(u_int32_t *, 5 * NFSX_UNSIGNED);
off = fxdr_hyper(tl);
@@ -1063,8 +1153,13 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
- if (v3)
+ if (v3) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
forat_ret = VOP_GETATTR(vp, &forat, cred, td);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
if (vp->v_type != VREG) {
if (v3)
error = EINVAL;
@@ -1074,7 +1169,11 @@ nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
if (!error)
error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1);
if (error) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
nfsm_reply(NFSX_WCCDATA(v3));
if (v3)
@@ -1083,6 +1182,7 @@ 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);
@@ -1116,12 +1216,18 @@ 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 */
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 */
aftat_ret = VOP_GETATTR(vp, vap, cred, td);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
if (!error)
error = aftat_ret;
@@ -1159,9 +1265,13 @@ ereply:
}
error = 0;
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (vp)
vput(vp);
vn_finished_write(mntp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return(error);
}
@@ -1195,6 +1305,8 @@ nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp,
u_quad_t cur_usec;
struct mount *mntp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
i = 0;
@@ -1348,8 +1460,13 @@ loop1:
error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
nfsd->nd_nam, &rdonly, TRUE);
if (!error) {
- if (v3)
+ if (v3) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
forat_ret = VOP_GETATTR(vp, &forat, cred, td);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
if (vp->v_type != VREG) {
if (v3)
error = EINVAL;
@@ -1361,6 +1478,7 @@ loop1:
}
if (!error)
error = nfsrv_access(vp, VWRITE, cred, rdonly, td, 1);
+ NFSD_UNLOCK();
if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
ioflags = IO_NODELOCKED;
else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
@@ -1372,6 +1490,7 @@ loop1:
uiop->uio_td = NULL;
uiop->uio_offset = nfsd->nd_off;
uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
+ mtx_lock(&Giant); /* VFS */
if (uiop->uio_resid > 0) {
mp = mrep;
i = 0;
@@ -1402,6 +1521,7 @@ loop1:
}
if (!error) {
error = VOP_WRITE(vp, uiop, ioflags, cred);
+ /* XXXRW: unlocked write. */
nfsrvstats.srvvop_writes++;
vn_finished_write(mntp);
}
@@ -1413,6 +1533,8 @@ loop1:
vput(vp);
vp = NULL;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
/*
* Loop around generating replies for all write rpcs that have
@@ -1507,6 +1629,8 @@ nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd)
struct mbuf *mp;
struct nfsrv_descript *p;
+ NFSD_LOCK_ASSERT();
+
NFS_DPF(WG, ("C%03x-%03x",
nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
LIST_REMOVE(nfsd, nd_hash);
@@ -1573,6 +1697,8 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
u_char cverf[NFSX_V3CREATEVERF];
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
rdev = 0;
@@ -1585,7 +1711,11 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@@ -1604,7 +1734,11 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
if (dirp && !v3) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(dirp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
dirp = NULL;
}
if (error) {
@@ -1679,6 +1813,8 @@ 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.
*/
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (nd.ni_vp == NULL) {
if (vap->va_mode == (mode_t)VNOVAL)
vap->va_mode = 0;
@@ -1797,6 +1933,8 @@ nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
}
}
ereply:
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
if (v3) {
if (!error) {
@@ -1813,6 +1951,8 @@ ereply:
error = 0;
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (nd.ni_startdir) {
vrele(nd.ni_startdir);
nd.ni_startdir = NULL;
@@ -1829,6 +1969,8 @@ nfsmout:
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -1858,6 +2000,8 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct mount *mp = NULL;
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv_mknod: v3 proc called on a v2 connection");
@@ -1869,7 +2013,11 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@@ -1915,6 +2063,8 @@ nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
vap->va_type = vtyp;
if (vap->va_mode == (mode_t)VNOVAL)
vap->va_mode = 0;
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (vtyp == VSOCK) {
vrele(nd.ni_startdir);
nd.ni_startdir = NULL;
@@ -1987,6 +2137,8 @@ out:
VOP_UNLOCK(dirp, 0, td);
}
ereply:
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
if (v3) {
if (!error) {
@@ -1995,9 +2147,15 @@ ereply:
}
nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (0);
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp)
vrele(dirp);
if (nd.ni_startdir)
@@ -2012,6 +2170,8 @@ nfsmout:
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -2037,6 +2197,8 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -2046,7 +2208,11 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
@@ -2054,6 +2220,8 @@ nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp && !v3) {
vrele(dirp);
dirp = NULL;
@@ -2099,6 +2267,8 @@ out:
vrele(dirp);
dirp = NULL;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
ereply:
nfsm_reply(NFSX_WCCDATA(v3));
if (v3) {
@@ -2106,6 +2276,8 @@ ereply:
error = 0;
}
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp) {
if (nd.ni_dvp == nd.ni_vp)
@@ -2116,6 +2288,8 @@ nfsmout:
if (nd.ni_vp)
vput(nd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return(error);
}
@@ -2144,6 +2318,8 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
uid_t saved_uid;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
#ifndef nolint
fvp = NULL;
@@ -2176,7 +2352,11 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
&dpos, &fdirp, v3, &fdirfor, &fdirfor_ret, td, FALSE);
if (fdirp && !v3) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(fdirp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
fdirp = NULL;
}
if (error) {
@@ -2197,6 +2377,8 @@ nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
&dpos, &tdirp, v3, &tdirfor, &tdirfor_ret, td, FALSE);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (tdirp && !v3) {
vrele(tdirp);
tdirp = NULL;
@@ -2282,9 +2464,13 @@ out:
/* fall through */
out1:
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(2 * NFSX_WCCDATA(v3));
if (v3) {
/* Release existing locks to prevent deadlock. */
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (tond.ni_dvp) {
if (tond.ni_dvp == tond.ni_vp)
vrele(tond.ni_dvp);
@@ -2306,6 +2492,8 @@ out1:
tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, td);
VOP_UNLOCK(tdirp, 0, td);
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
}
@@ -2316,6 +2504,8 @@ nfsmout:
/*
* Clear out tond related fields
*/
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (tdirp)
vrele(tdirp);
if (tond.ni_startdir)
@@ -2344,6 +2534,8 @@ nfsmout:
vrele(fromnd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -2369,6 +2561,8 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp, *dfhp;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -2379,7 +2573,11 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvmtofh(dfhp);
nfsm_srvnamesiz(len);
@@ -2394,6 +2592,8 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (v3)
getret = VOP_GETATTR(vp, &at, cred, td);
if (vp->v_type == VDIR) {
@@ -2404,8 +2604,12 @@ nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
nd.ni_cnd.cn_flags = LOCKPARENT;
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp && !v3) {
vrele(dirp);
dirp = NULL;
@@ -2459,6 +2663,8 @@ out2:
VOP_UNLOCK(dirp, 0, td);
}
}
+ mtx_lock(&Giant); /* VFS */
+ NFSD_LOCK();
ereply:
nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
if (v3) {
@@ -2469,6 +2675,8 @@ ereply:
/* fall through */
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
NDFREE(&nd, NDF_ONLY_PNBUF);
if (dirp)
vrele(dirp);
@@ -2483,6 +2691,8 @@ nfsmout:
if (nd.ni_vp)
vrele(nd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return(error);
}
@@ -2512,6 +2722,8 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -2521,13 +2733,19 @@ nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto out;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp && !v3) {
vrele(dirp);
dirp = NULL;
@@ -2626,6 +2844,8 @@ out:
vrele(nd.ni_startdir);
nd.ni_startdir = NULL;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
if (v3) {
if (!error) {
@@ -2638,6 +2858,8 @@ out:
/* fall through */
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
NDFREE(&nd, NDF_ONLY_PNBUF);
if (nd.ni_dvp) {
if (nd.ni_dvp == nd.ni_vp)
@@ -2655,6 +2877,8 @@ nfsmout:
FREE(pathcp, M_TEMP);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -2684,6 +2908,8 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -2693,7 +2919,11 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto out;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = CREATE;
@@ -2702,7 +2932,11 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
&dirp, v3, &dirfor, &dirfor_ret, td, FALSE);
if (dirp && !v3) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(dirp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
dirp = NULL;
}
if (error) {
@@ -2725,6 +2959,8 @@ nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
* nd.ni_vp, if it exists, is referenced but not locked.
*/
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vap->va_type = VDIR;
if (nd.ni_vp != NULL) {
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -2779,6 +3015,8 @@ out:
VOP_UNLOCK(dirp, 0, td);
}
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
if (v3) {
if (!error) {
@@ -2796,6 +3034,8 @@ out:
/* fall through */
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (dirp)
vrele(dirp);
if (nd.ni_dvp) {
@@ -2812,6 +3052,8 @@ nfsmout:
vrele(nd.ni_vp);
}
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -2837,6 +3079,8 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct nameidata nd;
struct mount *mp = NULL;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
ndclear(&nd);
@@ -2846,7 +3090,11 @@ nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto out;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_srvnamesiz(len);
nd.ni_cnd.cn_cred = cred;
nd.ni_cnd.cn_nameiop = DELETE;
@@ -2886,6 +3134,8 @@ out:
* Issue or abort op. Since SAVESTART is not set, path name
* component is freed by the VOP after either.
*/
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (!error)
error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
NDFREE(&nd, NDF_ONLY_PNBUF);
@@ -2910,6 +3160,8 @@ out:
VOP_UNLOCK(dirp, 0, td);
}
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
nfsm_reply(NFSX_WCCDATA(v3));
error = 0;
if (v3)
@@ -2917,6 +3169,8 @@ out:
/* fall through */
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
NDFREE(&nd, NDF_ONLY_PNBUF);
if (dirp)
vrele(dirp);
@@ -2930,6 +3184,8 @@ nfsmout:
vput(nd.ni_vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return(error);
}
@@ -2999,6 +3255,8 @@ nfsrv_readdir(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 */
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -3025,7 +3283,11 @@ 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 */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
}
if (error) {
@@ -3039,6 +3301,8 @@ 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 */
if (v3) {
error = getret = VOP_GETATTR(vp, &at, cred, td);
#if 0
@@ -3049,10 +3313,17 @@ nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = NFSERR_BAD_COOKIE;
#endif
}
- if (!error)
+ if (!error) {
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
+ }
if (error) {
vput(vp);
+ mtx_unlock(&Giant);
+ NFSD_LOCK();
vp = NULL;
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
@@ -3094,10 +3365,12 @@ again:
VOP_UNLOCK(vp, 0, td);
if (error) {
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
free((caddr_t)rbuf, M_TEMP);
if (cookies)
free((caddr_t)cookies, M_TEMP);
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3));
if (v3)
nfsm_srvpostop_attr(getret, &at);
@@ -3113,7 +3386,9 @@ again:
*/
if (siz == 0) {
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2 * NFSX_UNSIGNED);
if (v3) {
@@ -3161,6 +3436,8 @@ again:
goto again;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
len = 3 * NFSX_UNSIGNED; /* paranoia, probably can be 0 */
nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
if (v3) {
@@ -3237,7 +3514,11 @@ again:
cookiep++;
ncookies--;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
nfsm_clget;
*tl = nfsrv_nfs_false;
@@ -3257,8 +3538,13 @@ again:
FREE((caddr_t)cookies, M_TEMP);
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -3292,6 +3578,8 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
u_long *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv_readdirplus: v3 proc called on a v2 connection");
@@ -3315,8 +3603,12 @@ 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 */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
}
if (error) {
nfsm_reply(NFSX_UNSIGNED);
@@ -3324,6 +3616,8 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
error = getret = VOP_GETATTR(vp, &at, cred, td);
#if 0
/*
@@ -3332,10 +3626,17 @@ nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
if (!error && toff && verf && verf != at.va_filerev)
error = NFSERR_BAD_COOKIE;
#endif
- if (!error)
+ if (!error) {
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
error = nfsrv_access(vp, VEXEC, cred, rdonly, td, 0);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
+ }
if (error) {
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
nfsm_reply(NFSX_V3POSTOPATTR);
nfsm_srvpostop_attr(getret, &at);
@@ -3370,10 +3671,12 @@ again:
error = getret;
if (error) {
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
if (cookies)
free((caddr_t)cookies, M_TEMP);
free((caddr_t)rbuf, M_TEMP);
+ NFSD_LOCK();
nfsm_reply(NFSX_V3POSTOPATTR);
nfsm_srvpostop_attr(getret, &at);
error = 0;
@@ -3388,6 +3691,8 @@ again:
*/
if (siz == 0) {
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
vp = NULL;
nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2 * NFSX_UNSIGNED);
@@ -3441,19 +3746,23 @@ again:
EOPNOTSUPP) {
error = NFSERR_NOTSUPP;
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
free((caddr_t)cookies, M_TEMP);
free((caddr_t)rbuf, M_TEMP);
+ NFSD_LOCK();
nfsm_reply(NFSX_V3POSTOPATTR);
nfsm_srvpostop_attr(getret, &at);
error = 0;
goto nfsmout;
}
vput(nvp);
+ mtx_unlock(&Giant); /* VFS */
nvp = NULL;
dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2 * NFSX_UNSIGNED;
+ NFSD_LOCK();
nfsm_reply(cnt);
nfsm_srvpostop_attr(getret, &at);
tl = nfsm_build(u_int32_t *, 2 * NFSX_UNSIGNED);
@@ -3462,6 +3771,8 @@ again:
bp = bpos;
be = bp + M_TRAILINGSPACE(mp);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
/* Loop through the records and build reply */
while (cpos < cend && ncookies > 0) {
if (dp->d_fileno != 0 && dp->d_type != DT_WHT) {
@@ -3517,16 +3828,16 @@ again:
fl.fl_off.nfsuquad[0] = 0;
fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
- nfsm_clget;
+ nfsm_clget_nolock;
*tl = nfsrv_nfs_true;
bp += NFSX_UNSIGNED;
- nfsm_clget;
+ nfsm_clget_nolock;
*tl = 0;
bp += NFSX_UNSIGNED;
- nfsm_clget;
+ nfsm_clget_nolock;
*tl = txdr_unsigned(dp->d_fileno);
bp += NFSX_UNSIGNED;
- nfsm_clget;
+ nfsm_clget_nolock;
*tl = txdr_unsigned(nlen);
bp += NFSX_UNSIGNED;
@@ -3555,7 +3866,7 @@ again:
xfer = sizeof (struct flrep);
cp = (caddr_t)&fl;
while (xfer > 0) {
- nfsm_clget;
+ nfsm_clget_nolock;
if ((bp + xfer) > be)
tsiz = be - bp;
else
@@ -3574,10 +3885,12 @@ invalid:
ncookies--;
}
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
- nfsm_clget;
+ nfsm_clget_nolock;
*tl = nfsrv_nfs_false;
bp += NFSX_UNSIGNED;
+ NFSD_LOCK();
nfsm_clget;
if (eofflag)
*tl = nfsrv_nfs_true;
@@ -3592,8 +3905,13 @@ invalid:
FREE((caddr_t)cookies, M_TEMP);
FREE((caddr_t)rbuf, M_TEMP);
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vrele(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -3620,6 +3938,8 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct mount *mp = NULL;
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv_commit: v3 proc called on a v2 connection");
@@ -3629,7 +3949,11 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = ESTALE;
goto ereply;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
(void) vn_start_write(NULL, &mp, V_WAIT);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
tl = nfsm_dissect(u_int32_t *, 3 * NFSX_UNSIGNED);
/*
@@ -3646,6 +3970,8 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
for_ret = VOP_GETATTR(vp, &bfor, cred, td);
if (cnt > MAX_COMMIT_COUNT) {
@@ -3733,7 +4059,9 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
aft_ret = VOP_GETATTR(vp, &aft, cred, td);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
ereply:
nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
@@ -3747,9 +4075,13 @@ ereply:
error = 0;
}
nfsmout:
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
if (vp)
vput(vp);
vn_finished_write(mp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return(error);
}
@@ -3777,6 +4109,8 @@ nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct statfs statfs;
u_quad_t tval;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
fhp = &nfh.fh_generic;
nfsm_srvmtofh(fhp);
@@ -3789,10 +4123,14 @@ nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
goto nfsmout;
}
sf = &statfs;
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
error = VFS_STATFS(vp->v_mount, sf, td);
getret = VOP_GETATTR(vp, &at, cred, td);
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
if (v3)
nfsm_srvpostop_attr(getret, &at);
@@ -3838,8 +4176,13 @@ nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
}
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant);
vput(vp);
+ mtx_unlock(&Giant);
+ NFSD_LOCK();
+ }
return(error);
}
@@ -3866,6 +4209,8 @@ nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
struct statfs sb;
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv_fsinfo: v3 proc called on a v2 connection");
@@ -3879,13 +4224,17 @@ nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
/* 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 */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
nfsm_srvpostop_attr(getret, &at);
sip = nfsm_build(struct nfsv3_fsinfo *, NFSX_V3FSINFO);
@@ -3913,8 +4262,13 @@ nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
NFSV3FSINFO_CANSETTIME);
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -3940,6 +4294,8 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
fhandle_t *fhp;
int v3 = (nfsd->nd_flag & ND_NFSV3);
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (!v3)
panic("nfsrv_pathconf: v3 proc called on a v2 connection");
@@ -3952,6 +4308,8 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
error = 0;
goto nfsmout;
}
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
if (!error)
error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
@@ -3961,7 +4319,9 @@ 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 */
vp = NULL;
+ NFSD_LOCK();
nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
nfsm_srvpostop_attr(getret, &at);
if (error) {
@@ -3983,8 +4343,13 @@ nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
pc->pc_caseinsensitive = nfsrv_nfs_false;
pc->pc_casepreserving = nfsrv_nfs_true;
nfsmout:
- if (vp)
+ if (vp) {
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
vput(vp);
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ }
return(error);
}
@@ -4001,6 +4366,8 @@ nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
int error = NFSERR_RETVOID;
struct mbuf *mb, *mreq;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
nfsm_reply(0);
nfsmout:
@@ -4020,6 +4387,8 @@ nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
int error;
struct mbuf *mb, *mreq;
+ NFSD_LOCK_ASSERT();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (nfsd->nd_repstat)
error = nfsd->nd_repstat;
@@ -4052,6 +4421,9 @@ nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
struct vattr vattr;
int error;
+ NFSD_LOCK_ASSERT();
+ NFSD_UNLOCK();
+
nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
if (flags & VWRITE) {
/* Just vn_writechk() changed to check rdonly */
@@ -4065,7 +4437,8 @@ nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
case VREG:
case VDIR:
case VLNK:
- return (EROFS);
+ error = EROFS;
+ goto out;
default:
break;
}
@@ -4074,12 +4447,15 @@ nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
* If there's shared text associated with
* the inode, we can't allow writing.
*/
- if (vp->v_vflag & VV_TEXT)
+ if (vp->v_vflag & VV_TEXT) {
+ NFSD_LOCK();
return (ETXTBSY);
+ }
}
+ mtx_lock(&Giant); /* VFS */
error = VOP_GETATTR(vp, &vattr, cred, td);
if (error)
- return (error);
+ goto out2;
error = VOP_ACCESS(vp, flags, cred, td);
/*
* Allow certain operations for the owner (reads and writes
@@ -4087,5 +4463,9 @@ nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
*/
if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
error = 0;
+out2:
+ mtx_unlock(&Giant); /* VFS */
+out:
+ NFSD_LOCK();
return error;
}
diff --git a/sys/nfsserver/nfs_srvcache.c b/sys/nfsserver/nfs_srvcache.c
index f0e940d..e82625e 100644
--- a/sys/nfsserver/nfs_srvcache.c
+++ b/sys/nfsserver/nfs_srvcache.c
@@ -44,7 +44,9 @@ __FBSDID("$FreeBSD$");
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/systm.h>
+#include <sys/lock.h>
#include <sys/mbuf.h>
+#include <sys/mutex.h>
#include <sys/socket.h>
#include <sys/socketvar.h> /* for sodupsockaddr */
@@ -72,7 +74,7 @@ static u_long nfsrvhash;
/*
* Static array that defines which nfs rpc's are nonidempotent
*/
-static int nonidempotent[NFS_NPROCS] = {
+static const int nonidempotent[NFS_NPROCS] = {
FALSE,
FALSE,
TRUE,
@@ -99,7 +101,7 @@ static int nonidempotent[NFS_NPROCS] = {
};
/* True iff the rpc reply is an nfs status ONLY! */
-static int nfsv2_repstat[NFS_NPROCS] = {
+static const int nfsv2_repstat[NFS_NPROCS] = {
FALSE,
FALSE,
FALSE,
@@ -154,6 +156,8 @@ nfsrv_getcache(struct nfsrv_descript *nd, struct mbuf **repp)
caddr_t bpos;
int ret;
+ NFSD_LOCK_ASSERT();
+
/*
* Don't cache recent requests for reliable transport protocols.
* (Maybe we should for the case of a reconnect, but..)
@@ -167,7 +171,8 @@ loop:
NFS_DPF(RC, ("H%03x", rp->rc_xid & 0xfff));
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
- (void) tsleep(rp, PZERO-1, "nfsrc", 0);
+ (void) msleep(rp, &nfsd_mtx, PZERO-1,
+ "nfsrc", 0);
goto loop;
}
rp->rc_flag |= RC_LOCKED;
@@ -188,8 +193,10 @@ loop:
ret = RC_REPLY;
} else if (rp->rc_flag & RC_REPMBUF) {
nfsrvstats.srvcache_nonidemdonehits++;
+ NFSD_UNLOCK();
*repp = m_copym(rp->rc_reply, 0, M_COPYALL,
M_TRYWAIT);
+ NFSD_LOCK();
ret = RC_REPLY;
} else {
nfsrvstats.srvcache_idemdonehits++;
@@ -207,15 +214,17 @@ loop:
nfsrvstats.srvcache_misses++;
NFS_DPF(RC, ("M%03x", nd->nd_retxid & 0xfff));
if (numnfsrvcache < desirednfsrvcache) {
+ NFSD_UNLOCK();
rp = (struct nfsrvcache *)malloc((u_long)sizeof *rp,
M_NFSD, M_WAITOK | M_ZERO);
+ NFSD_LOCK();
numnfsrvcache++;
rp->rc_flag = RC_LOCKED;
} else {
rp = TAILQ_FIRST(&nfsrvlruhead);
while ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
- (void) tsleep(rp, PZERO-1, "nfsrc", 0);
+ (void) msleep(rp, &nfsd_mtx, PZERO-1, "nfsrc", 0);
rp = TAILQ_FIRST(&nfsrvlruhead);
}
rp->rc_flag |= RC_LOCKED;
@@ -261,6 +270,8 @@ nfsrv_updatecache(struct nfsrv_descript *nd, int repvalid, struct mbuf *repmbuf)
{
struct nfsrvcache *rp;
+ NFSD_LOCK_ASSERT();
+
if (!nd->nd_nam2)
return;
loop:
@@ -270,7 +281,8 @@ loop:
NFS_DPF(RC, ("U%03x", rp->rc_xid & 0xfff));
if ((rp->rc_flag & RC_LOCKED) != 0) {
rp->rc_flag |= RC_WANTED;
- (void) tsleep(rp, PZERO-1, "nfsrc", 0);
+ (void) msleep(rp, &nfsd_mtx, PZERO-1,
+ "nfsrc", 0);
goto loop;
}
rp->rc_flag |= RC_LOCKED;
@@ -298,8 +310,10 @@ loop:
rp->rc_status = nd->nd_repstat;
rp->rc_flag |= RC_REPSTATUS;
} else {
+ NFSD_UNLOCK();
rp->rc_reply = m_copym(repmbuf,
0, M_COPYALL, M_TRYWAIT);
+ NFSD_LOCK();
rp->rc_flag |= RC_REPMBUF;
}
}
@@ -322,6 +336,8 @@ nfsrv_cleancache(void)
{
struct nfsrvcache *rp, *nextrp;
+ NFSD_LOCK_ASSERT();
+
for (rp = TAILQ_FIRST(&nfsrvlruhead); rp != 0; rp = nextrp) {
nextrp = TAILQ_NEXT(rp, rc_lru);
LIST_REMOVE(rp, rc_hash);
diff --git a/sys/nfsserver/nfs_srvsock.c b/sys/nfsserver/nfs_srvsock.c
index 32a42b2..d43b97a 100644
--- a/sys/nfsserver/nfs_srvsock.c
+++ b/sys/nfsserver/nfs_srvsock.c
@@ -97,7 +97,7 @@ struct callout nfsrv_callout;
static void nfs_realign(struct mbuf **pm, int hsiz); /* XXX SHARED */
static int nfsrv_getstream(struct nfssvc_sock *, int);
-int (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
+int32_t (*nfsrv3_procs[NFS_NPROCS])(struct nfsrv_descript *nd,
struct nfssvc_sock *slp,
struct thread *td,
struct mbuf **mreqp) = {
@@ -140,9 +140,13 @@ nfs_rephead(int siz, struct nfsrv_descript *nd, int err,
caddr_t bpos;
struct mbuf *mb;
+ /* XXXRW: not 100% clear the lock is needed here. */
+ NFSD_LOCK_ASSERT();
+
nd->nd_repstat = err;
if (err && (nd->nd_flag & ND_NFSV3) == 0) /* XXX recheck */
siz = 0;
+ NFSD_UNLOCK();
MGETHDR(mreq, M_TRYWAIT, MT_DATA);
mb = mreq;
/*
@@ -155,6 +159,7 @@ nfs_rephead(int siz, struct nfsrv_descript *nd, int err,
MCLGET(mreq, M_TRYWAIT);
} else
mreq->m_data += min(max_hdr, M_TRAILINGSPACE(mreq));
+ NFSD_LOCK();
tl = mtod(mreq, u_int32_t *);
bpos = ((caddr_t)tl) + mreq->m_len;
*tl++ = txdr_unsigned(nd->nd_retxid);
@@ -236,13 +241,18 @@ nfs_realign(struct mbuf **pm, int hsiz) /* XXX COMMON */
struct mbuf *n = NULL;
int off = 0;
+ /* XXXRW: may not need lock? */
+ NFSD_LOCK_ASSERT();
+
++nfs_realign_test;
while ((m = *pm) != NULL) {
if ((m->m_len & 0x3) || (mtod(m, intptr_t) & 0x3)) {
+ NFSD_UNLOCK();
MGET(n, M_TRYWAIT, MT_DATA);
if (m->m_len >= MINCLSIZE) {
MCLGET(n, M_TRYWAIT);
}
+ NFSD_LOCK();
n->m_len = 0;
break;
}
@@ -281,6 +291,8 @@ nfs_getreq(struct nfsrv_descript *nd, struct nfsd *nfsd, int has_header)
int error = 0;
struct mbuf *mrep, *md;
+ NFSD_LOCK_ASSERT();
+
mrep = nd->nd_mrep;
md = nd->nd_md;
dpos = nd->nd_dpos;
@@ -410,6 +422,15 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
struct uio auio;
int flags, error;
+ /*
+ * XXXRW: For now, assert Giant here since the NFS server upcall
+ * will perform socket operations requiring Giant in a non-mpsafe
+ * kernel.
+ */
+ NET_ASSERT_GIANT();
+ NFSD_UNLOCK_ASSERT();
+
+ /* XXXRW: Unlocked read. */
if ((slp->ns_flag & SLP_VALID) == 0)
return;
#ifdef notdef
@@ -417,12 +438,13 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
* Define this to test for nfsds handling this under heavy load.
*/
if (waitflag == M_DONTWAIT) {
+ NFSD_LOCK();
slp->ns_flag |= SLP_NEEDQ;
goto dorecs;
}
#endif
- GIANT_REQUIRED; /* XXX until socket locking is done */
+ NFSD_LOCK();
auio.uio_td = NULL;
if (so->so_type == SOCK_STREAM) {
/*
@@ -441,8 +463,10 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
*/
auio.uio_resid = 1000000000;
flags = MSG_DONTWAIT;
+ NFSD_UNLOCK();
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, &nam, &auio, &mp, NULL, &flags);
+ NFSD_LOCK();
if (error || mp == NULL) {
if (error == EWOULDBLOCK)
slp->ns_flag |= SLP_NEEDQ;
@@ -476,6 +500,7 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
do {
auio.uio_resid = 1000000000;
flags = MSG_DONTWAIT;
+ NFSD_UNLOCK();
error = so->so_proto->pr_usrreqs->pru_soreceive
(so, &nam, &auio, &mp, NULL, &flags);
if (mp) {
@@ -487,13 +512,16 @@ nfsrv_rcv(struct socket *so, void *arg, int waitflag)
if (nam)
FREE(nam, M_SONAME);
m_freem(mp);
+ NFSD_LOCK();
continue;
}
+ NFSD_LOCK();
nfs_realign(&mp, 10 * NFSX_UNSIGNED);
rec->nr_address = nam;
rec->nr_packet = mp;
STAILQ_INSERT_TAIL(&slp->ns_rec, rec, nr_link);
- }
+ } else
+ NFSD_LOCK();
if (error) {
if ((so->so_proto->pr_flags & PR_CONNREQUIRED)
&& error != EWOULDBLOCK) {
@@ -512,6 +540,7 @@ dorecs:
(STAILQ_FIRST(&slp->ns_rec) != NULL ||
(slp->ns_flag & (SLP_NEEDQ | SLP_DISCONN))))
nfsrv_wakenfsd(slp);
+ NFSD_UNLOCK();
}
/*
@@ -528,6 +557,8 @@ nfsrv_getstream(struct nfssvc_sock *slp, int waitflag)
struct mbuf *om, *m2, *recm;
u_int32_t recmark;
+ NFSD_LOCK_ASSERT();
+
if (slp->ns_flag & SLP_GETSTREAM)
panic("nfs getstream");
slp->ns_flag |= SLP_GETSTREAM;
@@ -586,8 +617,10 @@ nfsrv_getstream(struct nfssvc_sock *slp, int waitflag)
while (len < slp->ns_reclen) {
if ((len + m->m_len) > slp->ns_reclen) {
+ NFSD_UNLOCK();
m2 = m_copym(m, 0, slp->ns_reclen - len,
waitflag);
+ NFSD_LOCK();
if (m2) {
if (om) {
om->m_next = m2;
@@ -630,8 +663,10 @@ nfsrv_getstream(struct nfssvc_sock *slp, int waitflag)
*mpp = recm;
if (slp->ns_flag & SLP_LASTFRAG) {
struct nfsrv_rec *rec;
+ NFSD_UNLOCK();
rec = malloc(sizeof(struct nfsrv_rec), M_NFSRVDESC,
waitflag == M_DONTWAIT ? M_NOWAIT : M_WAITOK);
+ NFSD_LOCK();
if (!rec) {
m_freem(slp->ns_frag);
} else {
@@ -658,6 +693,8 @@ nfsrv_dorec(struct nfssvc_sock *slp, struct nfsd *nfsd,
struct nfsrv_descript *nd;
int error;
+ NFSD_LOCK_ASSERT();
+
*ndp = NULL;
if ((slp->ns_flag & SLP_VALID) == 0 ||
STAILQ_FIRST(&slp->ns_rec) == NULL)
@@ -667,8 +704,10 @@ nfsrv_dorec(struct nfssvc_sock *slp, struct nfsd *nfsd,
nam = rec->nr_address;
m = rec->nr_packet;
free(rec, M_NFSRVDESC);
+ NFSD_UNLOCK();
MALLOC(nd, struct nfsrv_descript *, sizeof (struct nfsrv_descript),
M_NFSRVDESC, M_WAITOK);
+ NFSD_LOCK();
nd->nd_md = nd->nd_mrep = m;
nd->nd_nam2 = nam;
nd->nd_dpos = mtod(m, caddr_t);
@@ -695,6 +734,8 @@ nfsrv_wakenfsd(struct nfssvc_sock *slp)
{
struct nfsd *nd;
+ NFSD_LOCK_ASSERT();
+
if ((slp->ns_flag & SLP_VALID) == 0)
return;
TAILQ_FOREACH(nd, &nfsd_head, nfsd_chain) {
@@ -725,7 +766,8 @@ nfsrv_send(struct socket *so, struct sockaddr *nam, struct mbuf *top)
struct sockaddr *sendnam;
int error, soflags, flags;
- GIANT_REQUIRED; /* XXX until socket locking is done */
+ NET_ASSERT_GIANT();
+ NFSD_UNLOCK_ASSERT();
soflags = so->so_proto->pr_flags;
if ((soflags & PR_CONNREQUIRED) || (so->so_state & SS_ISCONNECTED))
@@ -766,6 +808,7 @@ nfsrv_timer(void *arg)
u_quad_t cur_usec;
s = splnet();
+ NFSD_LOCK();
/*
* Scan the write gathering queues for writes that need to be
* completed now.
@@ -776,6 +819,7 @@ nfsrv_timer(void *arg)
LIST_FIRST(&slp->ns_tq)->nd_time <= cur_usec)
nfsrv_wakenfsd(slp);
}
+ NFSD_UNLOCK();
splx(s);
callout_reset(&nfsrv_callout, nfsrv_ticks, nfsrv_timer, NULL);
}
diff --git a/sys/nfsserver/nfs_srvsubs.c b/sys/nfsserver/nfs_srvsubs.c
index 9da4b1a..7217150 100644
--- a/sys/nfsserver/nfs_srvsubs.c
+++ b/sys/nfsserver/nfs_srvsubs.c
@@ -85,8 +85,8 @@ u_int32_t nfsrv_rpc_call, nfsrv_rpc_vers, nfsrv_rpc_reply,
u_int32_t nfsrv_nfs_prog, nfsrv_nfs_true, nfsrv_nfs_false;
/* And other global data */
-static nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK,
- NFNON, NFCHR, NFNON };
+static const nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR,
+ NFLNK, NFNON, NFCHR, NFNON };
#define vtonfsv2_type(a) txdr_unsigned(nfsv2_type[((int32_t)(a))])
#define vtonfsv3_mode(m) txdr_unsigned((m) & ALLPERMS)
@@ -100,10 +100,12 @@ int nfsd_head_flag;
static int nfs_prev_nfssvc_sy_narg;
static sy_call_t *nfs_prev_nfssvc_sy_call;
+struct mtx nfsd_mtx;
+
/*
* Mapping of old NFS Version 2 RPC numbers to generic numbers.
*/
-int nfsrv_nfsv3_procid[NFS_NPROCS] = {
+const int nfsrv_nfsv3_procid[NFS_NPROCS] = {
NFSPROC_NULL,
NFSPROC_GETATTR,
NFSPROC_SETATTR,
@@ -132,7 +134,7 @@ int nfsrv_nfsv3_procid[NFS_NPROCS] = {
/*
* and the reverse mapping from generic to Version 2 procedure numbers
*/
-int nfsrvv2_procid[NFS_NPROCS] = {
+const int nfsrvv2_procid[NFS_NPROCS] = {
NFSV2PROC_NULL,
NFSV2PROC_GETATTR,
NFSV2PROC_SETATTR,
@@ -163,7 +165,7 @@ int nfsrvv2_procid[NFS_NPROCS] = {
* Use 0 (which gets converted to NFSERR_IO) as the catch all for ones not
* specifically defined in RFC 1094.
*/
-static u_char nfsrv_v2errmap[ELAST] = {
+static const u_char nfsrv_v2errmap[ELAST] = {
NFSERR_PERM, NFSERR_NOENT, 0, 0, 0,
NFSERR_NXIO, 0, 0, 0, 0,
0, 0, NFSERR_ACCES, 0, 0,
@@ -192,12 +194,12 @@ static u_char nfsrv_v2errmap[ELAST] = {
* The first entry is the default error return and the rest are the valid
* errors for that RPC in increasing numeric order.
*/
-static short nfsv3err_null[] = {
+static const short nfsv3err_null[] = {
0,
0,
};
-static short nfsv3err_getattr[] = {
+static const short nfsv3err_getattr[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_STALE,
@@ -206,7 +208,7 @@ static short nfsv3err_getattr[] = {
0,
};
-static short nfsv3err_setattr[] = {
+static const short nfsv3err_setattr[] = {
NFSERR_IO,
NFSERR_PERM,
NFSERR_IO,
@@ -222,7 +224,7 @@ static short nfsv3err_setattr[] = {
0,
};
-static short nfsv3err_lookup[] = {
+static const short nfsv3err_lookup[] = {
NFSERR_IO,
NFSERR_NOENT,
NFSERR_IO,
@@ -235,7 +237,7 @@ static short nfsv3err_lookup[] = {
0,
};
-static short nfsv3err_access[] = {
+static const short nfsv3err_access[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_STALE,
@@ -244,7 +246,7 @@ static short nfsv3err_access[] = {
0,
};
-static short nfsv3err_readlink[] = {
+static const short nfsv3err_readlink[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -256,7 +258,7 @@ static short nfsv3err_readlink[] = {
0,
};
-static short nfsv3err_read[] = {
+static const short nfsv3err_read[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_NXIO,
@@ -268,7 +270,7 @@ static short nfsv3err_read[] = {
0,
};
-static short nfsv3err_write[] = {
+static const short nfsv3err_write[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -283,7 +285,7 @@ static short nfsv3err_write[] = {
0,
};
-static short nfsv3err_create[] = {
+static const short nfsv3err_create[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -300,7 +302,7 @@ static short nfsv3err_create[] = {
0,
};
-static short nfsv3err_mkdir[] = {
+static const short nfsv3err_mkdir[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -317,7 +319,7 @@ static short nfsv3err_mkdir[] = {
0,
};
-static short nfsv3err_symlink[] = {
+static const short nfsv3err_symlink[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -334,7 +336,7 @@ static short nfsv3err_symlink[] = {
0,
};
-static short nfsv3err_mknod[] = {
+static const short nfsv3err_mknod[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -352,7 +354,7 @@ static short nfsv3err_mknod[] = {
0,
};
-static short nfsv3err_remove[] = {
+static const short nfsv3err_remove[] = {
NFSERR_IO,
NFSERR_NOENT,
NFSERR_IO,
@@ -366,7 +368,7 @@ static short nfsv3err_remove[] = {
0,
};
-static short nfsv3err_rmdir[] = {
+static const short nfsv3err_rmdir[] = {
NFSERR_IO,
NFSERR_NOENT,
NFSERR_IO,
@@ -384,7 +386,7 @@ static short nfsv3err_rmdir[] = {
0,
};
-static short nfsv3err_rename[] = {
+static const short nfsv3err_rename[] = {
NFSERR_IO,
NFSERR_NOENT,
NFSERR_IO,
@@ -407,7 +409,7 @@ static short nfsv3err_rename[] = {
0,
};
-static short nfsv3err_link[] = {
+static const short nfsv3err_link[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -427,7 +429,7 @@ static short nfsv3err_link[] = {
0,
};
-static short nfsv3err_readdir[] = {
+static const short nfsv3err_readdir[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -440,7 +442,7 @@ static short nfsv3err_readdir[] = {
0,
};
-static short nfsv3err_readdirplus[] = {
+static const short nfsv3err_readdirplus[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_ACCES,
@@ -454,7 +456,7 @@ static short nfsv3err_readdirplus[] = {
0,
};
-static short nfsv3err_fsstat[] = {
+static const short nfsv3err_fsstat[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_STALE,
@@ -463,7 +465,7 @@ static short nfsv3err_fsstat[] = {
0,
};
-static short nfsv3err_fsinfo[] = {
+static const short nfsv3err_fsinfo[] = {
NFSERR_STALE,
NFSERR_STALE,
NFSERR_BADHANDLE,
@@ -471,7 +473,7 @@ static short nfsv3err_fsinfo[] = {
0,
};
-static short nfsv3err_pathconf[] = {
+static const short nfsv3err_pathconf[] = {
NFSERR_STALE,
NFSERR_STALE,
NFSERR_BADHANDLE,
@@ -479,7 +481,7 @@ static short nfsv3err_pathconf[] = {
0,
};
-static short nfsv3err_commit[] = {
+static const short nfsv3err_commit[] = {
NFSERR_IO,
NFSERR_IO,
NFSERR_STALE,
@@ -488,7 +490,7 @@ static short nfsv3err_commit[] = {
0,
};
-static short *nfsrv_v3errmap[] = {
+static const short *nfsrv_v3errmap[] = {
nfsv3err_null,
nfsv3err_getattr,
nfsv3err_setattr,
@@ -520,8 +522,11 @@ static int
nfsrv_modevent(module_t mod, int type, void *data)
{
+ NET_LOCK_GIANT();
+
switch (type) {
case MOD_LOAD:
+ mtx_init(&nfsd_mtx, "nfsd_mtx", NULL, MTX_DEF);
nfsrv_rpc_vers = txdr_unsigned(RPC_VER2);
nfsrv_rpc_call = txdr_unsigned(RPC_CALL);
nfsrv_rpc_reply = txdr_unsigned(RPC_REPLY);
@@ -538,10 +543,11 @@ nfsrv_modevent(module_t mod, int type, void *data)
if (nfsrv_ticks < 1)
nfsrv_ticks = 1;
- nfsrv_init(0); /* Init server data structures */
nfsrv_initcache(); /* Init the server request cache */
-
+ NFSD_LOCK();
+ nfsrv_init(0); /* Init server data structures */
callout_init(&nfsrv_callout, 0);
+ NFSD_UNLOCK();
nfsrv_timer(0);
nfs_prev_nfssvc_sy_narg = sysent[SYS_nfssvc].sy_narg;
@@ -557,8 +563,10 @@ nfsrv_modevent(module_t mod, int type, void *data)
callout_stop(&nfsrv_callout);
sysent[SYS_nfssvc].sy_narg = nfs_prev_nfssvc_sy_narg;
sysent[SYS_nfssvc].sy_call = nfs_prev_nfssvc_sy_call;
+ mtx_destroy(&nfsd_mtx);
break;
}
+ NET_UNLOCK_GIANT();
return 0;
}
static moduledata_t nfsserver_mod = {
@@ -603,6 +611,10 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
struct componentname *cnp = &ndp->ni_cnd;
int lockleaf = (cnp->cn_flags & LOCKLEAF) != 0;
+ NFSD_LOCK_ASSERT();
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
+
*retdirp = NULL;
cnp->cn_flags |= NOMACCHECK;
cnp->cn_pnbuf = uma_zalloc(namei_zone, M_WAITOK);
@@ -646,8 +658,12 @@ nfs_namei(struct nameidata *ndp, fhandle_t *fhp, int len,
/*
* Extract and set starting directory.
*/
+ 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;
if (dp->v_type != VDIR) {
@@ -868,6 +884,8 @@ out:
} else if ((ndp->ni_cnd.cn_flags & (WANTPARENT|LOCKPARENT)) == 0) {
ndp->ni_dvp = NULL;
}
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
return (error);
}
@@ -882,6 +900,8 @@ nfsm_adj(struct mbuf *mp, int len, int nul)
int count, i;
char *cp;
+ NFSD_LOCK_DONTCARE();
+
/*
* Trim from tail. Scan the mbuf chain,
* calculating its length and finding the last mbuf.
@@ -1043,6 +1063,8 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
struct sockaddr_int *saddr;
#endif
+ NFSD_LOCK_ASSERT();
+
*vpp = NULL;
if (nfs_ispublicfh(fhp)) {
@@ -1054,12 +1076,14 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
mp = vfs_getvfs(&fhp->fh_fsid);
if (!mp)
return (ESTALE);
+ NFSD_UNLOCK();
+ mtx_lock(&Giant); /* VFS */
error = VFS_CHECKEXP(mp, nam, &exflags, &credanon);
if (error)
- return (error);
+ goto out;
error = VFS_FHTOVP(mp, &fhp->fh_fid, vpp);
if (error)
- return (error);
+ goto out;
#ifdef MNT_EXNORESPORT
if (!(exflags & (MNT_EXNORESPORT|MNT_EXPUBLIC))) {
saddr = (struct sockaddr_in *)nam;
@@ -1069,7 +1093,7 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
ntohs(saddr->sin_port) >= IPPORT_RESERVED) {
vput(*vpp);
*vpp = NULL;
- return (NFSERR_AUTHERR | AUTH_TOOWEAK);
+ error = NFSERR_AUTHERR | AUTH_TOOWEAK;
}
}
#endif
@@ -1091,7 +1115,10 @@ nfsrv_fhtovp(fhandle_t *fhp, int lockflag, struct vnode **vpp,
if (!lockflag)
VOP_UNLOCK(*vpp, 0, td);
- return (0);
+out:
+ mtx_unlock(&Giant); /* VFS */
+ NFSD_LOCK();
+ return (error);
}
@@ -1106,6 +1133,8 @@ nfs_ispublicfh(fhandle_t *fhp)
char *cp = (char *)fhp;
int i;
+ NFSD_LOCK_DONTCARE();
+
for (i = 0; i < NFSX_V3FH; i++)
if (*cp++ != 0)
return (FALSE);
@@ -1124,6 +1153,8 @@ netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
{
struct sockaddr_in *inetaddr;
+ NFSD_LOCK_DONTCARE();
+
switch (family) {
case AF_INET:
inetaddr = (struct sockaddr_in *)nam;
@@ -1159,9 +1190,11 @@ netaddr_match(int family, union nethostaddr *haddr, struct sockaddr *nam)
int
nfsrv_errmap(struct nfsrv_descript *nd, int err)
{
- short *defaulterrp, *errp;
+ const short *defaulterrp, *errp;
int e;
+ NFSD_LOCK_DONTCARE();
+
if (nd->nd_flag & ND_NFSV3) {
if (nd->nd_procnum <= NFSPROC_COMMIT) {
errp = defaulterrp = nfsrv_v3errmap[nd->nd_procnum];
@@ -1187,6 +1220,9 @@ int
nfsrv_object_create(struct vnode *vp)
{
+ GIANT_REQUIRED;
+ NFSD_UNLOCK_ASSERT();
+
if (vp == NULL || vp->v_type != VREG)
return (1);
return (vfs_object_create(vp, curthread, curthread->td_ucred));
@@ -1203,6 +1239,8 @@ nfsrvw_sort(gid_t *list, int num)
int i, j;
gid_t v;
+ NFSD_LOCK_DONTCARE();
+
/* Insertion sort. */
for (i = 1; i < num; i++) {
v = list[i];
@@ -1221,6 +1259,8 @@ nfsrv_setcred(struct ucred *incred, struct ucred *outcred)
{
int i;
+ NFSD_LOCK_DONTCARE();
+
bzero((caddr_t)outcred, sizeof (struct ucred));
outcred->cr_ref = 1;
outcred->cr_uid = incred->cr_uid;
@@ -1239,6 +1279,8 @@ nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb, caddr_t *bpos)
{
u_int32_t *tl;
+ NFSD_LOCK_DONTCARE();
+
if (v3) {
tl = nfsm_build_xx(NFSX_UNSIGNED + NFSX_V3FH, mb, bpos);
*tl++ = txdr_unsigned(NFSX_V3FH);
@@ -1265,6 +1307,8 @@ nfsm_srvstrsiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
{
u_int32_t *tl;
+ NFSD_LOCK_DONTCARE();
+
tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
@@ -1279,6 +1323,8 @@ nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
{
u_int32_t *tl;
+ NFSD_LOCK_DONTCARE();
+
tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
@@ -1292,15 +1338,26 @@ nfsm_srvnamesiz_xx(int *s, int m, struct mbuf **md, caddr_t *dpos)
void
nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
- char **bp, char **be, caddr_t bpos)
+ char **bp, char **be, caddr_t bpos, int droplock)
{
struct mbuf *nmp;
+ NFSD_LOCK_DONTCARE();
+
+ if (droplock)
+ NFSD_LOCK_ASSERT();
+ else
+ NFSD_UNLOCK_ASSERT();
+
if (*bp >= *be) {
if (*mp == mb)
(*mp)->m_len += *bp - bpos;
+ if (droplock)
+ NFSD_UNLOCK();
MGET(nmp, M_TRYWAIT, MT_DATA);
MCLGET(nmp, M_TRYWAIT);
+ if (droplock)
+ NFSD_LOCK();
nmp->m_len = NFSMSIZ(nmp);
(*mp)->m_next = nmp;
*mp = nmp;
@@ -1317,6 +1374,8 @@ nfsm_srvmtofh_xx(fhandle_t *f, struct nfsrv_descript *nfsd, struct mbuf **md,
u_int32_t *tl;
int fhlen;
+ NFSD_LOCK_DONTCARE();
+
if (nfsd->nd_flag & ND_NFSV3) {
tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
@@ -1343,6 +1402,8 @@ nfsm_srvsattr_xx(struct vattr *a, struct mbuf **md, caddr_t *dpos)
{
u_int32_t *tl;
+ NFSD_LOCK_DONTCARE();
+
tl = nfsm_dissect_xx(NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
diff --git a/sys/nfsserver/nfs_syscalls.c b/sys/nfsserver/nfs_syscalls.c
index c3b097e..19ef606 100644
--- a/sys/nfsserver/nfs_syscalls.c
+++ b/sys/nfsserver/nfs_syscalls.c
@@ -142,11 +142,14 @@ nfssvc(struct thread *td, struct nfssvc_args *uap)
error = suser(td);
if (error)
return (error);
- mtx_lock(&Giant);
+ NET_LOCK_GIANT();
+ NFSD_LOCK();
while (nfssvc_sockhead_flag & SLP_INIT) {
nfssvc_sockhead_flag |= SLP_WANTINIT;
- (void) tsleep(&nfssvc_sockhead, PSOCK, "nfsd init", 0);
+ (void) msleep(&nfssvc_sockhead, &nfsd_mtx, PSOCK,
+ "nfsd init", 0);
}
+ NFSD_UNLOCK();
if (uap->flag & NFSSVC_ADDSOCK) {
error = copyin(uap->argp, (caddr_t)&nfsdarg, sizeof(nfsdarg));
if (error)
@@ -180,7 +183,7 @@ nfssvc(struct thread *td, struct nfssvc_args *uap)
if (error == EINTR || error == ERESTART)
error = 0;
done2:
- mtx_unlock(&Giant);
+ NET_UNLOCK_GIANT();
return (error);
}
@@ -195,10 +198,14 @@ nfssvc_addsock(struct file *fp, struct sockaddr *mynam, struct thread *td)
struct socket *so;
int error, s;
- GIANT_REQUIRED; /* XXX until socket locking done */
+ NET_ASSERT_GIANT();
so = fp->f_data;
#if 0
+ /*
+ * XXXRW: If this code is ever enabled, there's a race when running
+ * MPSAFE.
+ */
tslp = NULL;
/*
* Add it to the list, as required.
@@ -263,12 +270,16 @@ nfssvc_addsock(struct file *fp, struct sockaddr *mynam, struct thread *td)
malloc(sizeof (struct nfssvc_sock), M_NFSSVC,
M_WAITOK | M_ZERO);
STAILQ_INIT(&slp->ns_rec);
+ NFSD_LOCK();
TAILQ_INSERT_TAIL(&nfssvc_sockhead, slp, ns_chain);
slp->ns_so = so;
slp->ns_nam = mynam;
fhold(fp);
slp->ns_fp = fp;
+ /*
+ * XXXRW: Socket locking here?
+ */
s = splnet();
so->so_upcallarg = (caddr_t)slp;
so->so_upcall = nfsrv_rcv;
@@ -276,6 +287,7 @@ nfssvc_addsock(struct file *fp, struct sockaddr *mynam, struct thread *td)
slp->ns_flag = (SLP_VALID | SLP_NEEDQ);
nfsrv_wakenfsd(slp);
splx(s);
+ NFSD_UNLOCK();
return (0);
}
@@ -295,6 +307,8 @@ nfssvc_nfsd(struct thread *td)
int procrastinate;
u_quad_t cur_usec;
+ NET_ASSERT_GIANT();
+
#ifndef nolint
cacherep = RC_DOIT;
writes_todo = 0;
@@ -302,6 +316,8 @@ nfssvc_nfsd(struct thread *td)
nfsd = (struct nfsd *)
malloc(sizeof (struct nfsd), M_NFSD, M_WAITOK | M_ZERO);
s = splnet();
+ NFSD_LOCK();
+
nfsd->nfsd_td = td;
TAILQ_INSERT_TAIL(&nfsd_head, nfsd, nfsd_chain);
nfsrv_numnfsd++;
@@ -315,8 +331,8 @@ nfssvc_nfsd(struct thread *td)
(nfsd_head_flag & NFSD_CHECKSLP) == 0) {
nfsd->nfsd_flag |= NFSD_WAITING;
nfsd_waiting++;
- error = tsleep(nfsd, PSOCK | PCATCH,
- "-", 0);
+ error = msleep(nfsd, &nfsd_mtx,
+ PSOCK | PCATCH, "-", 0);
nfsd_waiting--;
if (error)
goto done;
@@ -343,8 +359,10 @@ nfssvc_nfsd(struct thread *td)
else if (slp->ns_flag & SLP_NEEDQ) {
slp->ns_flag &= ~SLP_NEEDQ;
(void) nfs_slplock(slp, 1);
+ NFSD_UNLOCK();
nfsrv_rcv(slp->ns_so, (caddr_t)slp,
M_TRYWAIT);
+ NFSD_LOCK();
nfs_slpunlock(slp);
}
error = nfsrv_dorec(slp, nfsd, &nd);
@@ -458,6 +476,7 @@ nfssvc_nfsd(struct thread *td)
nd->nd_mrep = NULL;
/* FALLTHROUGH */
case RC_REPLY:
+ NFSD_UNLOCK();
siz = m_length(mreq, NULL);
if (siz <= 0 || siz > NFS_MAXPACKET) {
printf("mbuf siz=%d\n",siz);
@@ -474,11 +493,16 @@ nfssvc_nfsd(struct thread *td)
M_PREPEND(m, NFSX_UNSIGNED, M_TRYWAIT);
*mtod(m, u_int32_t *) = htonl(0x80000000 | siz);
}
+ NFSD_LOCK();
if (slp->ns_so->so_proto->pr_flags & PR_CONNREQUIRED)
(void) nfs_slplock(slp, 1);
- if (slp->ns_flag & SLP_VALID)
+ if (slp->ns_flag & SLP_VALID) {
+ NFSD_UNLOCK();
+ NET_LOCK_GIANT();
error = nfsrv_send(slp->ns_so, nd->nd_nam2, m);
- else {
+ NET_UNLOCK_GIANT();
+ NFSD_LOCK();
+ } else {
error = EPIPE;
m_freem(m);
}
@@ -535,6 +559,7 @@ done:
free((caddr_t)nfsd, M_NFSD);
if (--nfsrv_numnfsd == 0)
nfsrv_init(TRUE); /* Reinitialize everything */
+ NFSD_UNLOCK();
return (error);
}
@@ -554,9 +579,18 @@ nfsrv_zapsock(struct nfssvc_sock *slp)
struct nfsrv_rec *rec;
int s;
+ NET_ASSERT_GIANT();
+ NFSD_LOCK_ASSERT();
+
+ /*
+ * XXXRW: By clearing all flags, other threads/etc should ignore
+ * this slp and we can safely release nfsd_mtx so we can clean
+ * up the slp safely.
+ */
slp->ns_flag &= ~SLP_ALLFLAGS;
fp = slp->ns_fp;
if (fp) {
+ NFSD_UNLOCK();
slp->ns_fp = NULL;
so = slp->ns_so;
so->so_rcv.sb_flags &= ~SB_UPCALL;
@@ -564,6 +598,7 @@ nfsrv_zapsock(struct nfssvc_sock *slp)
so->so_upcallarg = NULL;
soshutdown(so, SHUT_RDWR);
closef(fp, NULL);
+ NFSD_LOCK();
if (slp->ns_nam)
FREE(slp->ns_nam, M_SONAME);
m_freem(slp->ns_raw);
@@ -593,6 +628,8 @@ void
nfsrv_slpderef(struct nfssvc_sock *slp)
{
+ NFSD_LOCK_ASSERT();
+
if (--(slp->ns_sref) == 0 && (slp->ns_flag & SLP_VALID) == 0) {
TAILQ_REMOVE(&nfssvc_sockhead, slp, ns_chain);
free((caddr_t)slp, M_NFSSVC);
@@ -601,17 +638,22 @@ nfsrv_slpderef(struct nfssvc_sock *slp)
/*
* Lock a socket against others.
+ *
+ * XXXRW: Wait argument is always 1 in the caller. Replace with a real
+ * sleep lock?
*/
int
nfs_slplock(struct nfssvc_sock *slp, int wait)
{
int *statep = &slp->ns_solock;
+ NFSD_LOCK_ASSERT();
+
if (!wait && (*statep & NFSRV_SNDLOCK))
return(0); /* already locked, fail */
while (*statep & NFSRV_SNDLOCK) {
*statep |= NFSRV_WANTSND;
- (void) tsleep(statep, PZERO - 1, "nfsslplck", 0);
+ (void) msleep(statep, &nfsd_mtx, PZERO - 1, "nfsslplck", 0);
}
*statep |= NFSRV_SNDLOCK;
return (1);
@@ -625,6 +667,8 @@ nfs_slpunlock(struct nfssvc_sock *slp)
{
int *statep = &slp->ns_solock;
+ NFSD_LOCK_ASSERT();
+
if ((*statep & NFSRV_SNDLOCK) == 0)
panic("nfs slpunlock");
*statep &= ~NFSRV_SNDLOCK;
@@ -644,6 +688,9 @@ nfsrv_init(int terminating)
{
struct nfssvc_sock *slp, *nslp;
+ NET_ASSERT_GIANT();
+ NFSD_LOCK_ASSERT();
+
if (nfssvc_sockhead_flag & SLP_INIT)
panic("nfsd init");
nfssvc_sockhead_flag |= SLP_INIT;
diff --git a/sys/nfsserver/nfsm_subs.h b/sys/nfsserver/nfsm_subs.h
index 07b958c..8e404d8 100644
--- a/sys/nfsserver/nfsm_subs.h
+++ b/sys/nfsserver/nfsm_subs.h
@@ -160,7 +160,7 @@ void nfsm_srvfhtom_xx(fhandle_t *f, int v3, struct mbuf **mb,
caddr_t *bpos);
void nfsm_srvpostop_fh_xx(fhandle_t *f, struct mbuf **mb, caddr_t *bpos);
void nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
- char **bp, char **be, caddr_t bpos);
+ char **bp, char **be, caddr_t bpos, int droplock);
#define nfsm_srvfhtom(f, v3) \
nfsm_srvfhtom_xx((f), (v3), &mb, &bpos)
@@ -178,6 +178,9 @@ void nfsm_clget_xx(u_int32_t **tl, struct mbuf *mb, struct mbuf **mp,
nfsm_srvfattr(nfsd, (a), (f))
#define nfsm_clget \
- nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos)
+ nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos, 1)
+
+#define nfsm_clget_nolock \
+ nfsm_clget_xx(&tl, mb, &mp, &bp, &be, bpos, 0)
#endif
OpenPOWER on IntegriCloud