diff options
author | Artur Grabowski <art@cvs.openbsd.org> | 2003-01-31 17:37:51 +0000 |
---|---|---|
committer | Artur Grabowski <art@cvs.openbsd.org> | 2003-01-31 17:37:51 +0000 |
commit | 1b0b18abe62afb1a61733a6f5891a98bfbea81ec (patch) | |
tree | 29dc896fd65580ea85012ef60aaf813858629e3f /sys/miscfs/kernfs | |
parent | 2bccdd51809becfe909c271f5fef4d380c663209 (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.c | 41 | ||||
-rw-r--r-- | sys/miscfs/kernfs/kernfs_vnops.c | 24 |
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*/ |