summaryrefslogtreecommitdiff
path: root/sys/miscfs/kernfs
diff options
context:
space:
mode:
authorArtur Grabowski <art@cvs.openbsd.org>2003-01-31 17:37:51 +0000
committerArtur Grabowski <art@cvs.openbsd.org>2003-01-31 17:37:51 +0000
commit1b0b18abe62afb1a61733a6f5891a98bfbea81ec (patch)
tree29dc896fd65580ea85012ef60aaf813858629e3f /sys/miscfs/kernfs
parent2bccdd51809becfe909c271f5fef4d380c663209 (diff)
File system locking fixups, mostly from NetBSD:
- cache_lookup move common code from various fs's here always return with vnode and parent locked adjust return codes - PDIRUNLOCK - new flag set if lookup couldn't lock parent vnode - kernfs and procfs lock vnode in get_root don't unlock (again) in kernfs_freevp fix memory leak in procfs From tedu@stanford.edu deraadt@ and various other ok
Diffstat (limited to 'sys/miscfs/kernfs')
-rw-r--r--sys/miscfs/kernfs/kernfs_vfsops.c41
-rw-r--r--sys/miscfs/kernfs/kernfs_vnops.c24
2 files changed, 41 insertions, 24 deletions
diff --git a/sys/miscfs/kernfs/kernfs_vfsops.c b/sys/miscfs/kernfs/kernfs_vfsops.c
index 68ded75d74b..561c2c4e904 100644
--- a/sys/miscfs/kernfs/kernfs_vfsops.c
+++ b/sys/miscfs/kernfs/kernfs_vfsops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kernfs_vfsops.c,v 1.19 2002/10/12 02:03:46 krw Exp $ */
+/* $OpenBSD: kernfs_vfsops.c,v 1.20 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: kernfs_vfsops.c,v 1.26 1996/04/22 01:42:27 christos Exp $ */
/*
@@ -102,7 +102,10 @@ kernfs_mount(mp, path, data, ndp, p)
struct nameidata *ndp;
struct proc *p;
{
+ int error = 0;
size_t size;
+ struct vnode *rvp;
+ struct kern_target *kt;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_mount(mp = %p)\n", mp);
@@ -114,7 +117,17 @@ kernfs_mount(mp, path, data, ndp, p)
if (mp->mnt_flag & MNT_UPDATE)
return (EOPNOTSUPP);
+ kt = kernfs_findtarget(".", 1);
+ error = kernfs_allocvp(kt, mp, &rvp);
+ if (error)
+ return (error);
+
+ rvp->v_type = VDIR;
+ rvp->v_flag |= VROOT;
+
mp->mnt_flag |= MNT_LOCAL;
+ mp->mnt_data = (qaddr_t)rvp;
+ vrele(rvp);
vfs_getnewfsid(mp);
(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
@@ -158,8 +171,12 @@ kernfs_unmount(mp, mntflags, p)
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_unmount: calling vflush\n");
#endif
- if ((error = vflush(mp, 0, flags)) != 0)
+
+ if ((error = vflush(mp, 0, flags)) != 0) {
return (error);
+ }
+
+ mp->mnt_data = 0;
return (0);
}
@@ -169,24 +186,16 @@ kernfs_root(mp, vpp)
struct mount *mp;
struct vnode **vpp;
{
- struct kern_target *kt;
- int error;
+ struct vnode *vp = (struct vnode *)mp->mnt_data;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_root(mp = %p)\n", mp);
#endif
- kt = kernfs_findtarget(".", 1);
- /* this should never happen */
- if (kt == NULL)
- panic("kernfs_root: findtarget returned NULL");
-
- error = kernfs_allocvp(kt, mp, vpp);
- /* this should never happen */
- if (error)
- panic("kernfs_root: couldn't find root");
-
- return(0);
-
+
+ vget(vp, LK_EXCLUSIVE | LK_RETRY, curproc);
+ *vpp = vp;
+
+ return (0);
}
int
diff --git a/sys/miscfs/kernfs/kernfs_vnops.c b/sys/miscfs/kernfs/kernfs_vnops.c
index 269c0842653..3db0fadc84e 100644
--- a/sys/miscfs/kernfs/kernfs_vnops.c
+++ b/sys/miscfs/kernfs/kernfs_vnops.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kernfs_vnops.c,v 1.28 2002/10/12 02:03:46 krw Exp $ */
+/* $OpenBSD: kernfs_vnops.c,v 1.29 2003/01/31 17:37:50 art Exp $ */
/* $NetBSD: kernfs_vnops.c,v 1.43 1996/03/16 23:52:47 christos Exp $ */
/*
@@ -287,7 +287,6 @@ kernfs_freevp(vp, p)
struct kernfs_node *kf = VTOKERN(vp);
TAILQ_REMOVE(&kfshead, kf, list);
- VOP_UNLOCK(vp, 0, p);
FREE(vp->v_data, M_TEMP);
vp->v_data = 0;
return(0);
@@ -487,15 +486,16 @@ kernfs_lookup(v)
struct proc *p = cnp->cn_proc;
struct kern_target *kt;
struct vnode *vp;
- int error;
+ int error, wantpunlock;
#ifdef KERNFS_DIAGNOSTIC
printf("kernfs_lookup(%p)\n", ap);
printf("kernfs_lookup(dp = %p, vpp = %p, cnp = %p)\n", dvp, vpp, ap->a_cnp);
printf("kernfs_lookup(%s)\n", pname);
#endif
- VOP_UNLOCK(dvp, 0, p);
+
*vpp = NULLVP;
+ cnp->cn_flags &= ~PDIRUNLOCK;
if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)
return (EROFS);
@@ -503,14 +503,14 @@ kernfs_lookup(v)
if (cnp->cn_namelen == 1 && *pname == '.') {
*vpp = dvp;
VREF(dvp);
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return (0);
}
+ wantpunlock = (~cnp->cn_flags & (LOCKPARENT | ISLASTCN));
+
kt = kernfs_findtarget(pname, cnp->cn_namelen);
if (kt == NULL) {
/* not found */
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return(cnp->cn_nameiop == LOOKUP ? ENOENT : EROFS);
}
@@ -524,17 +524,25 @@ kernfs_lookup(v)
*vpp = vp;
if (vget(vp, LK_EXCLUSIVE, p))
goto loop;
+ if (wantpunlock) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
return(0);
}
if ((error = kernfs_allocvp(kt, dvp->v_mount, vpp)) != 0) {
- vn_lock(dvp, LK_SHARED | LK_RETRY, p);
return(error);
}
vn_lock(*vpp, LK_SHARED | LK_RETRY, p);
- return(error);
+
+ if (wantpunlock) {
+ VOP_UNLOCK(dvp, 0, p);
+ cnp->cn_flags |= PDIRUNLOCK;
+ }
+ return (0);
}
/*ARGSUSED*/