summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/nfs/nfs_node.c36
-rw-r--r--sys/nfs/nfs_vfsops.c4
-rw-r--r--sys/nfs/nfs_vnops.c167
-rw-r--r--sys/nfs/nfsnode.h9
4 files changed, 160 insertions, 56 deletions
diff --git a/sys/nfs/nfs_node.c b/sys/nfs/nfs_node.c
index 9d858658dc7..ba0156fb7ab 100644
--- a/sys/nfs/nfs_node.c
+++ b/sys/nfs/nfs_node.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_node.c,v 1.21 2002/01/23 00:39:48 art Exp $ */
+/* $OpenBSD: nfs_node.c,v 1.22 2002/02/22 20:19:14 csapuntz Exp $ */
/* $NetBSD: nfs_node.c,v 1.16 1996/02/18 11:53:42 fvdl Exp $ */
/*
@@ -145,6 +145,8 @@ loop:
vp = nvp;
np = pool_get(&nfs_node_pool, PR_WAITOK);
bzero((caddr_t)np, sizeof *np);
+ lockinit(&np->n_lock, PINOD, "nfsvlock", 0, 0);
+ lockmgr(&np->n_lock, LK_EXCLUSIVE, 0, p);
vp->v_data = np;
np->n_vnode = vp;
@@ -194,19 +196,32 @@ nfs_inactive(v)
np->n_sillyrename = (struct sillyrename *)0;
} else
sp = (struct sillyrename *)0;
- if (sp) {
- /*
- * Remove the silly file that was rename'd earlier
- */
+
+ /*
+ * Remove the silly file that was rename'd earlier
+ */
+ if (sp)
(void) nfs_vinvalbuf(ap->a_vp, 0, sp->s_cred, p, 1);
- nfs_removeit(sp);
+
+ np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
+
+ VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
+
+ if (sp) {
+ /* Note: sp->s_dvp may already be locked somewhere up in
+ the call stack as _inactive is called from many places
+ in the code. Thus, this call below requires that
+ recursive locks be enabled in vn_lock.
+ */
+ int error = vn_lock(sp->s_dvp, LK_EXCLUSIVE, ap->a_p);
+ if (error == 0) {
+ nfs_removeit(sp);
+ vput(sp->s_dvp);
+ }
crfree(sp->s_cred);
- vrele(sp->s_dvp);
- FREE((caddr_t)sp, M_NFSREQ);
+ FREE((caddr_t)sp, M_NFSREQ);
}
- np->n_flag &= (NMODIFIED | NFLUSHINPROG | NFLUSHWANT);
- VOP_UNLOCK(ap->a_vp, 0, ap->a_p);
return (0);
}
@@ -256,4 +271,3 @@ nfs_reclaim(v)
vp->v_data = NULL;
return (0);
}
-
diff --git a/sys/nfs/nfs_vfsops.c b/sys/nfs/nfs_vfsops.c
index 439cf624d34..6a2ede14b32 100644
--- a/sys/nfs/nfs_vfsops.c
+++ b/sys/nfs/nfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_vfsops.c,v 1.45 2002/02/10 22:02:05 nate Exp $ */
+/* $OpenBSD: nfs_vfsops.c,v 1.46 2002/02/22 20:19:14 csapuntz Exp $ */
/* $NetBSD: nfs_vfsops.c,v 1.46.4.1 1996/05/25 22:40:35 fvdl Exp $ */
/*
@@ -181,7 +181,7 @@ nfs_statfs(mp, sbp, p)
}
strncpy(&sbp->f_fstypename[0], mp->mnt_vfc->vfc_name, MFSNAMELEN);
nfsm_reqdone;
- vrele(vp);
+ vput(vp);
crfree(cred);
return (error);
}
diff --git a/sys/nfs/nfs_vnops.c b/sys/nfs/nfs_vnops.c
index c4dd3e30242..fd83fbe2135 100644
--- a/sys/nfs/nfs_vnops.c
+++ b/sys/nfs/nfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfs_vnops.c,v 1.47 2002/01/16 21:51:16 ericj Exp $ */
+/* $OpenBSD: nfs_vnops.c,v 1.48 2002/02/22 20:19:14 csapuntz Exp $ */
/* $NetBSD: nfs_vnops.c,v 1.62.4.1 1996/07/08 20:26:52 jtc Exp $ */
/*
@@ -693,6 +693,7 @@ nfs_lookup(v)
nfsfh_t *fhp;
struct nfsnode *np;
int lockparent, wantparent, error = 0, attrflag, fhsize;
+ int dvp_locked = 1;
int v3 = NFS_ISV3(dvp);
*vpp = NULLVP;
@@ -701,10 +702,9 @@ nfs_lookup(v)
return (EROFS);
if (dvp->v_type != VDIR)
return (ENOTDIR);
- lockparent = flags & LOCKPARENT;
+ lockparent = ((flags & (LOCKPARENT | ISLASTCN)) == (LOCKPARENT | ISLASTCN));
wantparent = flags & (LOCKPARENT|WANTPARENT);
nmp = VFSTONFS(dvp->v_mount);
- np = VTONFS(dvp);
if ((error = cache_lookup(dvp, vpp, cnp)) != 0 && error != ENOENT) {
struct vattr vattr;
int vpid;
@@ -718,10 +718,19 @@ nfs_lookup(v)
if (dvp == newvp) {
VREF(newvp);
error = 0;
- } else
+ } else if (flags & ISDOTDOT) {
+ VOP_UNLOCK(dvp, 0, p);
+ dvp_locked = 0;
+ error = vget(newvp, LK_EXCLUSIVE, p);
+ if (error != 0)
+ newvp = NULL;
+ } else {
error = vget(newvp, LK_EXCLUSIVE, p);
+ if (error != 0)
+ newvp = NULL;
+ }
- if (!error) {
+ if (error == 0) {
if (vpid == newvp->v_id) {
if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, cnp->cn_proc)
&& vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
@@ -729,15 +738,30 @@ nfs_lookup(v)
if (cnp->cn_nameiop != LOOKUP &&
(flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
- return (0);
+ goto exit;
}
cache_purge(newvp);
}
- vrele(newvp);
}
*vpp = NULLVP;
+
+ if (newvp == dvp)
+ vrele(newvp);
+ else if (newvp != NULL)
+ vput(newvp);
+
+ if (!dvp_locked) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ dvp_locked = 1;
+ }
+ }
+
+ np = VTONFS(dvp);
+ if (np == NULL) {
+ error = ERESTART;
+ goto exit;
}
- error = 0;
+ error = 0;
newvp = NULLVP;
nfsstats.lookupcache_misses++;
nfsstats.rpccnt[NFSPROC_LOOKUP]++;
@@ -760,12 +784,13 @@ nfs_lookup(v)
if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
if (NFS_CMPFH(np, fhp, fhsize)) {
m_freem(mrep);
- return (EISDIR);
+ error = EISDIR;
+ goto exit;
}
error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
if (error) {
m_freem(mrep);
- return (error);
+ goto exit;
}
newvp = NFSTOV(np);
if (v3) {
@@ -776,7 +801,8 @@ nfs_lookup(v)
*vpp = newvp;
m_freem(mrep);
cnp->cn_flags |= SAVENAME;
- return (0);
+ error = 0;
+ goto exit;
}
if (NFS_CMPFH(np, fhp, fhsize)) {
@@ -786,7 +812,7 @@ nfs_lookup(v)
error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
if (error) {
m_freem(mrep);
- return (error);
+ goto exit;
}
newvp = NFSTOV(np);
}
@@ -805,8 +831,6 @@ nfs_lookup(v)
*vpp = newvp;
nfsm_reqdone;
if (error) {
- if (newvp != NULLVP)
- vrele(newvp);
if ((cnp->cn_nameiop == CREATE || cnp->cn_nameiop == RENAME) &&
(flags & ISLASTCN) && error == ENOENT) {
if (dvp->v_mount->mnt_flag & MNT_RDONLY)
@@ -817,6 +841,25 @@ nfs_lookup(v)
if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
cnp->cn_flags |= SAVENAME;
}
+
+ exit:
+ if (error != 0) {
+ if (newvp == dvp) {
+ vrele(newvp);
+ } else if (newvp != NULL) {
+ vput(newvp);
+ }
+ }
+
+ if (!dvp_locked) {
+ if (error != 0 || lockparent) {
+ vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
+ }
+ } else {
+ if (error == 0 && !lockparent) {
+ VOP_UNLOCK(dvp, 0, p);
+ }
+ }
return (error);
}
@@ -1128,7 +1171,7 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
nfsm_mtofh(dvp, newvp, v3, gotvp);
if (!gotvp) {
if (newvp) {
- vrele(newvp);
+ vput(newvp);
newvp = (struct vnode *)0;
}
error = nfs_lookitup(dvp, cnp->cn_nameptr,
@@ -1141,8 +1184,10 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
nfsm_wcc_data(dvp, wccflag);
nfsm_reqdone;
if (error) {
- if (newvp)
- vrele(newvp);
+ if (newvp) {
+ vput(newvp);
+ newvp = NULL;
+ }
} else {
if (cnp->cn_flags & MAKEENTRY)
cache_enter(dvp, newvp, cnp);
@@ -1152,7 +1197,7 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
VTONFS(dvp)->n_flag |= NMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
+ vput(dvp);
return (error);
}
@@ -1175,8 +1220,9 @@ nfs_mknod(v)
int error;
error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
- if (!error)
- vrele(newvp);
+ if (error == 0)
+ vput(newvp);
+
return (error);
}
@@ -1252,7 +1298,7 @@ again:
nfsm_mtofh(dvp, newvp, v3, gotvp);
if (!gotvp) {
if (newvp) {
- vrele(newvp);
+ vput(newvp);
newvp = (struct vnode *)0;
}
error = nfs_lookitup(dvp, cnp->cn_nameptr,
@@ -1270,7 +1316,7 @@ again:
goto again;
}
if (newvp)
- vrele(newvp);
+ vput(newvp);
} else if (v3 && (fmode & O_EXCL))
error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_proc);
if (!error) {
@@ -1282,7 +1328,7 @@ again:
VTONFS(dvp)->n_flag |= NMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
+ vput(dvp);
return (error);
}
@@ -1354,8 +1400,8 @@ nfs_remove(v)
error = nfs_sillyrename(dvp, vp, cnp);
FREE(cnp->cn_pnbuf, M_NAMEI);
np->n_attrstamp = 0;
- vrele(dvp);
- vrele(vp);
+ vput(dvp);
+ vput(vp);
return (error);
}
@@ -1366,7 +1412,7 @@ int
nfs_removeit(sp)
struct sillyrename *sp;
{
-
+
return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen, sp->s_cred,
(struct proc *)0));
}
@@ -1446,7 +1492,7 @@ nfs_rename(v)
*/
if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
- vrele(tvp);
+ vput(tvp);
tvp = NULL;
}
@@ -1654,12 +1700,12 @@ nfs_symlink(v)
}
nfsm_reqdone;
if (newvp)
- vrele(newvp);
+ vput(newvp);
FREE(cnp->cn_pnbuf, M_NAMEI);
VTONFS(dvp)->n_flag |= NMODIFIED;
if (!wccflag)
VTONFS(dvp)->n_attrstamp = 0;
- vrele(dvp);
+ vput(dvp);
/*
* Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
*/
@@ -1729,7 +1775,7 @@ nfs_mkdir(v)
*/
if (error == EEXIST || (!error && !gotvp)) {
if (newvp) {
- vrele(newvp);
+ vput(newvp);
newvp = (struct vnode *)0;
}
error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
@@ -1742,11 +1788,11 @@ nfs_mkdir(v)
}
if (error) {
if (newvp)
- vrele(newvp);
+ vput(newvp);
} else
*ap->a_vpp = newvp;
FREE(cnp->cn_pnbuf, M_NAMEI);
- vrele(dvp);
+ vput(dvp);
return (error);
}
@@ -1775,7 +1821,7 @@ nfs_rmdir(v)
if (dvp == vp) {
vrele(dvp);
- vrele(dvp);
+ vput(dvp);
FREE(cnp->cn_pnbuf, M_NAMEI);
return (EINVAL);
}
@@ -1794,8 +1840,8 @@ nfs_rmdir(v)
VTONFS(dvp)->n_attrstamp = 0;
cache_purge(dvp);
cache_purge(vp);
- vrele(vp);
- vrele(dvp);
+ vput(vp);
+ vput(dvp);
/*
* Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
*/
@@ -2342,7 +2388,7 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
nfsm_adv(nfsm_rndup(i));
}
if (newvp != NULLVP) {
- vrele(newvp);
+ vput(newvp);
newvp = NULLVP;
}
nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
@@ -2383,7 +2429,7 @@ nfs_readdirplusrpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
nfsmout:
if (newvp != NULLVP)
- vrele(newvp);
+ vput(newvp);
return (error);
}
@@ -2507,7 +2553,7 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
nfsm_postop_attr(newvp, attrflag);
if (!attrflag && *npp == NULL) {
m_freem(mrep);
- vrele(newvp);
+ vput(newvp);
return (ENOENT);
}
} else
@@ -2517,7 +2563,7 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
if (npp && *npp == NULL) {
if (error) {
if (newvp)
- vrele(newvp);
+ vput(newvp);
} else
*npp = np;
}
@@ -3181,3 +3227,46 @@ nfsfifo_close(v)
return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap));
}
#endif /* ! FIFO */
+
+
+int
+nfs_lock(v)
+ void *v;
+{
+ struct vop_lock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ sturct proc *a_p;
+ } */ *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+ return (lockmgr(&VTONFS(vp)->n_lock, ap->a_flags, &vp->v_interlock,
+ ap->a_p));
+}
+
+int
+nfs_unlock(v)
+ void *v;
+{
+ struct vop_unlock_args /* {
+ struct vnode *a_vp;
+ int a_flags;
+ struct proc *a_p;
+ } */ *ap = v;
+ struct vnode *vp = ap->a_vp;
+
+ return (lockmgr(&VTONFS(vp)->n_lock, ap->a_flags | LK_RELEASE,
+ &vp->v_interlock, ap->a_p));
+}
+
+int
+nfs_islocked(v)
+ void *v;
+{
+ struct vop_islocked_args /* {
+ struct vnode *a_vp;
+ } */ *ap = v;
+
+ return (lockstatus(&VTONFS(ap->a_vp)->n_lock));
+}
+
diff --git a/sys/nfs/nfsnode.h b/sys/nfs/nfsnode.h
index 17c02979154..e1a8e41e57d 100644
--- a/sys/nfs/nfsnode.h
+++ b/sys/nfs/nfsnode.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: nfsnode.h,v 1.13 2001/12/19 08:58:06 art Exp $ */
+/* $OpenBSD: nfsnode.h,v 1.14 2002/02/22 20:19:14 csapuntz Exp $ */
/* $NetBSD: nfsnode.h,v 1.16 1996/02/18 11:54:04 fvdl Exp $ */
/*
@@ -119,6 +119,7 @@ struct nfsnode {
nfsfh_t n_fh; /* Small File Handle */
struct ucred *n_rcred;
struct ucred *n_wcred;
+ struct lock n_lock;
};
#define n_atim n_un1.nf_atim
@@ -187,9 +188,9 @@ int nfs_readdir __P((void *));
int nfs_readlink __P((void *));
int nfs_inactive __P((void *));
int nfs_reclaim __P((void *));
-#define nfs_lock ((int (*) __P((void *)))vop_generic_lock)
-#define nfs_unlock ((int (*) __P((void *)))vop_generic_unlock)
-#define nfs_islocked ((int (*) __P((void *)))vop_generic_islocked)
+int nfs_lock __P((void *));
+int nfs_unlock __P((void *));
+int nfs_islocked __P((void *));
int nfs_bmap __P((void *));
int nfs_strategy __P((void *));
int nfs_print __P((void *));