diff options
author | kato <kato@FreeBSD.org> | 1997-04-14 05:13:55 +0000 |
---|---|---|
committer | kato <kato@FreeBSD.org> | 1997-04-14 05:13:55 +0000 |
commit | 49921c887d0a1bd605725a6b38d7f6c7d7078a5f (patch) | |
tree | f426c39e57af1e1038d97fb55b67f5d296c74ef4 /sys/fs/unionfs/union_vnops.c | |
parent | 05ac2f5194eb187a3d330758891fa194e5a285e0 (diff) | |
download | FreeBSD-src-49921c887d0a1bd605725a6b38d7f6c7d7078a5f.zip FreeBSD-src-49921c887d0a1bd605725a6b38d7f6c7d7078a5f.tar.gz |
Fix locking violation when accessing `..'.
Obtained from: NetBSD
Diffstat (limited to 'sys/fs/unionfs/union_vnops.c')
-rw-r--r-- | sys/fs/unionfs/union_vnops.c | 40 |
1 files changed, 39 insertions, 1 deletions
diff --git a/sys/fs/unionfs/union_vnops.c b/sys/fs/unionfs/union_vnops.c index 9658eb1..e05372f 100644 --- a/sys/fs/unionfs/union_vnops.c +++ b/sys/fs/unionfs/union_vnops.c @@ -35,7 +35,7 @@ * SUCH DAMAGE. * * @(#)union_vnops.c 8.32 (Berkeley) 6/23/95 - * $Id: union_vnops.c,v 1.21 1997/04/13 06:29:13 phk Exp $ + * $Id: union_vnops.c,v 1.22 1997/04/13 13:12:12 kato Exp $ */ #include <sys/param.h> @@ -245,8 +245,40 @@ union_lookup(ap) */ if (upperdvp != NULLVP) { FIXUP(dun, p); + /* + * If we're doing `..' in the underlying filesystem, + * we must drop our lock on the union node before + * going up the tree in the lower file system--if we block + * on the lowervp lock, and that's held by someone else + * coming down the tree and who's waiting for our lock, + * we would be hosed. + */ + if (cnp->cn_flags & ISDOTDOT) { + /* retain lock on underlying VP: */ + dun->un_flags |= UN_KLOCK; + VOP_UNLOCK(dvp, 0, p); + } uerror = union_lookup1(um->um_uppervp, &upperdvp, &uppervp, cnp); + if (cnp->cn_flags & ISDOTDOT) { + if (dun->un_uppervp == upperdvp) { + /* + * We got the underlying bugger back locked... + * now take back the union node lock. Since we + * hold the uppervp lock, we can diddle union + * locking flags at will. :) + */ + dun->un_flags |= UN_ULOCK; + } + /* + * If upperdvp got swapped out, it means we did + * some mount point magic, and we do not have + * dun->un_uppervp locked currently--so we get it + * locked here (don't set the UN_ULOCK flag). + */ + VOP_LOCK(dvp, 0, p); + } + /*if (uppervp == upperdvp) dun->un_flags |= UN_KLOCK;*/ @@ -292,6 +324,12 @@ union_lookup(ap) saved_cred = cnp->cn_cred; cnp->cn_cred = um->um_cred; } + /* + * We shouldn't have to worry about locking interactions + * between the lower layer and our union layer (w.r.t. + * `..' processing) because we don't futz with lowervp + * locks in the union-node instantiation code path. + */ lerror = union_lookup1(um->um_lowervp, &lowerdvp, &lowervp, cnp); if (um->um_op == UNMNT_BELOW) |