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/adosfs/adlookup.c | |
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/adosfs/adlookup.c')
-rw-r--r-- | sys/adosfs/adlookup.c | 68 |
1 files changed, 27 insertions, 41 deletions
diff --git a/sys/adosfs/adlookup.c b/sys/adosfs/adlookup.c index 304d6aac08d..1c2896397e7 100644 --- a/sys/adosfs/adlookup.c +++ b/sys/adosfs/adlookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: adlookup.c,v 1.11 1997/12/18 00:59:01 gene Exp $ */ +/* $OpenBSD: adlookup.c,v 1.12 2003/01/31 17:37:49 art Exp $ */ /* $NetBSD: adlookup.c,v 1.17 1996/10/25 23:13:58 cgd Exp $ */ /* @@ -90,6 +90,7 @@ adosfs_lookup(v) *vpp = NULL; ucp = cnp->cn_cred; nameiop = cnp->cn_nameiop; + cnp->cn_flags &= ~PDIRUNLOCK; flags = cnp->cn_flags; last = flags & ISLASTCN; lockp = flags & LOCKPARENT; @@ -107,41 +108,17 @@ adosfs_lookup(v) return (ENOTDIR); if ((error = VOP_ACCESS(vdp, VEXEC, ucp, cnp->cn_proc)) != 0) return (error); + if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && + (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) + return (EROFS); + /* - * cache lookup algorithm borrowed from ufs_lookup() - * its not consistent with otherthings in this function.. + * Before tediously performing a linear scan of the directory, + * check the name cache to see if the directory/name pair + * we are looking for is known already. */ - if ((error = cache_lookup(vdp, vpp, cnp)) != 0) { - if (error == ENOENT) - return (error); - - vpid = (*vpp)->v_id; - if (vdp == *vpp) { - VREF(vdp); - error = 0; - } else if (flags & ISDOTDOT) { - VOP_UNLOCK(vdp, 0, p); /* race */ - error = vget(*vpp, LK_EXCLUSIVE, p); - if (error == 0 && lockp && last) - error = - vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p); - } else { - error = vget(*vpp, LK_EXCLUSIVE, p); - /* if (lockp == 0 || error || last) */ - if (lockp == 0 || error || last == 0) - VOP_UNLOCK(vdp, 0, p); - } - if (error == 0) { - if (vpid == vdp->v_id) - return (0); - vput(*vpp); - if (lockp && vdp != *vpp && last) - VOP_UNLOCK(vdp, 0, p); - } - *vpp = NULL; - if ((error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p)) != 0) - return (error); - } + if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) + return (error); /* * fake a '.' @@ -174,12 +151,17 @@ adosfs_lookup(v) * */ VOP_UNLOCK(vdp, 0, p); /* race */ + cnp->cn_flags |= PDIRUNLOCK; if ((error = VFS_VGET(vdp->v_mount, ABLKTOINO(adp->pblock), - vpp)) != 0) - vn_lock(vdp, LK_RETRY | LK_EXCLUSIVE, p); - else if (last && lockp && - (error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p))) - vput(*vpp); + vpp)) != 0) { + if (vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) + cnp->cn_flags &= ~PDIRUNLOCK; + } else if (last && lockp) { + if ((error = vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY, p))) + vput(*vpp); + else + cnp->cn_flags &= ~PDIRUNLOCK; + } if (error) { *vpp = NULL; return (error); @@ -238,8 +220,10 @@ adosfs_lookup(v) #endif return (error); } - if (lockp == 0) + if (lockp == 0) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } cnp->cn_nameiop |= SAVENAME; #ifdef ADOSFS_DIAGNOSTIC printf("EJUSTRETURN)"); @@ -278,8 +262,10 @@ found: } if (vdp == *vpp) VREF(vdp); - else if (lockp == 0 || last == 0) + else if (lockp == 0 || last == 0) { VOP_UNLOCK(vdp, 0, p); + cnp->cn_flags |= PDIRUNLOCK; + } found_lockdone: if ((cnp->cn_flags & MAKEENTRY) && nocache == 0) cache_enter(vdp, *vpp, cnp); |