summaryrefslogtreecommitdiffstats
path: root/sys/nfsclient/nfs_subs.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/nfsclient/nfs_subs.c')
-rw-r--r--sys/nfsclient/nfs_subs.c132
1 files changed, 108 insertions, 24 deletions
diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c
index fb67091..8556b3c 100644
--- a/sys/nfsclient/nfs_subs.c
+++ b/sys/nfsclient/nfs_subs.c
@@ -76,6 +76,12 @@ __FBSDID("$FreeBSD$");
#include <netinet/in.h>
/*
+ * Note that stdarg.h and the ANSI style va_start macro is used for both
+ * ANSI and traditional C compilers.
+ */
+#include <machine/stdarg.h>
+
+/*
* Data items converted to xdr at startup, since they are constant
* This is kinda hokey, but may save a little time doing byte swaps
*/
@@ -95,7 +101,6 @@ int nfs_pbuf_freecnt = -1; /* start out unlimited */
struct nfs_reqq nfs_reqq;
struct mtx nfs_reqq_mtx;
-struct mtx nfs_reply_mtx;
struct nfs_bufq nfs_bufq;
/*
@@ -182,6 +187,7 @@ nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
*/
tl = nfsm_build(u_int32_t *, 8 * NFSX_UNSIGNED);
+ mtx_lock(&nfs_reqq_mtx);
/* Get a pretty random xid to start with */
if (!nfs_xid)
nfs_xid = random();
@@ -193,6 +199,7 @@ nfsm_rpchead(struct ucred *cr, int nmflag, int procid, int auth_type,
*xidpp = tl;
*tl++ = txdr_unsigned(nfs_xid);
+ mtx_unlock(&nfs_reqq_mtx);
*tl++ = rpc_call;
*tl++ = rpc_vers;
*tl++ = txdr_unsigned(NFS_PROG);
@@ -416,7 +423,7 @@ nfs_init(struct vfsconf *vfsp)
TAILQ_INIT(&nfs_reqq);
callout_init(&nfs_callout, CALLOUT_MPSAFE);
mtx_init(&nfs_reqq_mtx, "NFS reqq lock", NULL, MTX_DEF);
- mtx_init(&nfs_reply_mtx, "Synch NFS reply posting", NULL, MTX_DEF);
+ mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF);
nfs_pbuf_freecnt = nswbuf / 2 + 1;
@@ -437,19 +444,80 @@ nfs_uninit(struct vfsconf *vfsp)
* Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup
* any sleeping nfsiods so they check nfs_iodmax and exit.
*/
+ mtx_lock(&nfs_iod_mtx);
nfs_iodmax = 0;
for (i = 0; i < nfs_numasync; i++)
if (nfs_iodwant[i])
wakeup(&nfs_iodwant[i]);
/* The last nfsiod to exit will wake us up when nfs_numasync hits 0 */
while (nfs_numasync)
- tsleep(&nfs_numasync, PWAIT, "ioddie", 0);
-
+ msleep(&nfs_numasync, &nfs_iod_mtx, PWAIT, "ioddie", 0);
+ mtx_unlock(&nfs_iod_mtx);
nfs_nhuninit();
uma_zdestroy(nfsmount_zone);
return (0);
}
+void
+nfs_dircookie_lock(struct nfsnode *np)
+{
+ mtx_lock(&np->n_mtx);
+ while (np->n_flag & NDIRCOOKIELK)
+ (void) msleep(&np->n_flag, &np->n_mtx, PZERO, "nfsdirlk", 0);
+ np->n_flag |= NDIRCOOKIELK;
+ mtx_unlock(&np->n_mtx);
+}
+
+void
+nfs_dircookie_unlock(struct nfsnode *np)
+{
+ mtx_lock(&np->n_mtx);
+ np->n_flag &= ~NDIRCOOKIELK;
+ wakeup(&np->n_flag);
+ mtx_unlock(&np->n_mtx);
+}
+
+int
+nfs_upgrade_vnlock(struct vnode *vp, struct thread *td)
+{
+ int old_lock;
+
+ if ((old_lock = VOP_ISLOCKED(vp, td)) != LK_EXCLUSIVE) {
+ if (old_lock == LK_SHARED) {
+ /* Upgrade to exclusive lock, this might block */
+ vn_lock(vp, LK_UPGRADE | LK_RETRY, td);
+ } else {
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
+ }
+ }
+ return old_lock;
+}
+
+void
+nfs_downgrade_vnlock(struct vnode *vp, struct thread *td, int old_lock)
+{
+ if (old_lock != LK_EXCLUSIVE) {
+ if (old_lock == LK_SHARED) {
+ /* Downgrade from exclusive lock, this might block */
+ vn_lock(vp, LK_DOWNGRADE, td);
+ } else {
+ VOP_UNLOCK(vp, 0, td);
+ }
+ }
+}
+
+void
+nfs_printf(const char *fmt, ...)
+{
+ va_list ap;
+
+ mtx_lock(&Giant);
+ va_start(ap, fmt);
+ printf(fmt, ap);
+ va_end(ap);
+ mtx_unlock(&Giant);
+}
+
/*
* Attribute cache routines.
* nfs_loadattrcache() - loads or updates the cache contents from attributes
@@ -466,7 +534,7 @@ nfs_uninit(struct vfsconf *vfsp)
*/
int
nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
- struct vattr *vaper, int dontshrink)
+ struct vattr *vaper, int dontshrink)
{
struct vnode *vp = *vpp;
struct vattr *vap;
@@ -535,6 +603,7 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
* information.
*/
np = VTONFS(vp);
+ mtx_lock(&np->n_mtx);
if (vp->v_type != vtyp) {
vp->v_type = vtyp;
if (vp->v_type == VFIFO)
@@ -617,6 +686,7 @@ nfs_loadattrcache(struct vnode **vpp, struct mbuf **mdp, caddr_t *dposp,
vaper->va_mtime = np->n_mtim;
}
}
+ mtx_unlock(&np->n_mtx);
return (0);
}
@@ -639,16 +709,20 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
struct vattr *vap;
struct nfsmount *nmp;
int timeo;
-
+
np = VTONFS(vp);
vap = &np->n_vattr;
nmp = VFSTONFS(vp->v_mount);
+#ifdef NFS_ACDEBUG
+ mtx_lock(&Giant); /* nfs_printf() */
+#endif
+ mtx_lock(&np->n_mtx);
/* XXX n_mtime doesn't seem to be updated on a miss-and-reload */
timeo = (time_second - np->n_mtime.tv_sec) / 10;
#ifdef NFS_ACDEBUG
if (nfs_acdebug>1)
- printf("nfs_getattrcache: initial timeo = %d\n", timeo);
+ nfs_printf("nfs_getattrcache: initial timeo = %d\n", timeo);
#endif
if (vap->va_type == VDIR) {
@@ -665,18 +739,19 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
#ifdef NFS_ACDEBUG
if (nfs_acdebug > 2)
- printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
- nmp->nm_acregmin, nmp->nm_acregmax,
- nmp->nm_acdirmin, nmp->nm_acdirmax);
+ nfs_printf("acregmin %d; acregmax %d; acdirmin %d; acdirmax %d\n",
+ nmp->nm_acregmin, nmp->nm_acregmax,
+ nmp->nm_acdirmin, nmp->nm_acdirmax);
if (nfs_acdebug)
- printf("nfs_getattrcache: age = %d; final timeo = %d\n",
- (time_second - np->n_attrstamp), timeo);
+ nfs_printf("nfs_getattrcache: age = %d; final timeo = %d\n",
+ (time_second - np->n_attrstamp), timeo);
#endif
if ((time_second - np->n_attrstamp) >= timeo) {
nfsstats.attrcache_misses++;
- return (ENOENT);
+ mtx_unlock(&np->n_mtx);
+ return( ENOENT);
}
nfsstats.attrcache_hits++;
if (vap->va_size != np->n_size) {
@@ -701,6 +776,10 @@ nfs_getattrcache(struct vnode *vp, struct vattr *vaper)
if (np->n_flag & NUPD)
vaper->va_mtime = np->n_mtim;
}
+ mtx_unlock(&np->n_mtx);
+#ifdef NFS_ACDEBUG
+ mtx_unlock(&Giant); /* nfs_printf() */
+#endif
return (0);
}
@@ -714,7 +793,8 @@ nfs_getcookie(struct nfsnode *np, off_t off, int add)
{
struct nfsdmap *dp, *dp2;
int pos;
-
+ nfsuint64 *retval = NULL;
+
pos = (uoff_t)off / NFS_DIRBLKSIZ;
if (pos == 0 || off < 0) {
#ifdef DIAGNOSTIC
@@ -732,14 +812,14 @@ nfs_getcookie(struct nfsnode *np, off_t off, int add)
dp->ndm_eocookie = 0;
LIST_INSERT_HEAD(&np->n_cookies, dp, ndm_list);
} else
- return (NULL);
+ goto out;
}
while (pos >= NFSNUMCOOKIES) {
pos -= NFSNUMCOOKIES;
if (LIST_NEXT(dp, ndm_list)) {
if (!add && dp->ndm_eocookie < NFSNUMCOOKIES &&
- pos >= dp->ndm_eocookie)
- return (NULL);
+ pos >= dp->ndm_eocookie)
+ goto out;
dp = LIST_NEXT(dp, ndm_list);
} else if (add) {
MALLOC(dp2, struct nfsdmap *, sizeof (struct nfsdmap),
@@ -748,15 +828,17 @@ nfs_getcookie(struct nfsnode *np, off_t off, int add)
LIST_INSERT_AFTER(dp, dp2, ndm_list);
dp = dp2;
} else
- return (NULL);
+ goto out;
}
if (pos >= dp->ndm_eocookie) {
if (add)
dp->ndm_eocookie = pos + 1;
else
- return (NULL);
+ goto out;
}
- return (&dp->ndm_cookies[pos]);
+ retval = &dp->ndm_cookies[pos];
+out:
+ return (retval);
}
/*
@@ -773,11 +855,13 @@ nfs_invaldir(struct vnode *vp)
if (vp->v_type != VDIR)
panic("nfs: invaldir not dir");
#endif
+ nfs_dircookie_lock(np);
np->n_direofoffset = 0;
np->n_cookieverf.nfsuquad[0] = 0;
np->n_cookieverf.nfsuquad[1] = 0;
if (LIST_FIRST(&np->n_cookies))
LIST_FIRST(&np->n_cookies)->ndm_eocookie = 0;
+ nfs_dircookie_unlock(np);
}
/*
@@ -797,8 +881,6 @@ nfs_clearcommit(struct mount *mp)
struct buf *bp, *nbp;
int s;
- GIANT_REQUIRED;
-
s = splbio();
MNT_ILOCK(mp);
MNT_VNODE_FOREACH(vp, mp, nvp) {
@@ -896,7 +978,7 @@ nfsm_getfh_xx(nfsfh_t **f, int *s, int v3, struct mbuf **md, caddr_t *dpos)
int
nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md,
- caddr_t *dpos)
+ caddr_t *dpos)
{
int t1;
@@ -910,7 +992,7 @@ nfsm_loadattr_xx(struct vnode **v, struct vattr *va, struct mbuf **md,
int
nfsm_postop_attr_xx(struct vnode **v, int *f, struct mbuf **md,
- caddr_t *dpos)
+ caddr_t *dpos)
{
u_int32_t *tl;
int t1;
@@ -945,9 +1027,11 @@ nfsm_wcc_data_xx(struct vnode **v, int *f, struct mbuf **md, caddr_t *dpos)
tl = nfsm_dissect_xx(6 * NFSX_UNSIGNED, md, dpos);
if (tl == NULL)
return EBADRPC;
+ mtx_lock(&(VTONFS(*v))->n_mtx);
if (*f)
ttretf = (VTONFS(*v)->n_mtime.tv_sec == fxdr_unsigned(u_int32_t, *(tl + 2)) &&
VTONFS(*v)->n_mtime.tv_nsec == fxdr_unsigned(u_int32_t, *(tl + 3)));
+ mtx_unlock(&(VTONFS(*v))->n_mtx);
}
t1 = nfsm_postop_attr_xx(v, &ttattrf, md, dpos);
if (t1)
OpenPOWER on IntegriCloud