Fix PR5146: reboot with working directory in unionfs causes

"panic: lockmgr: using decommisioned lock"
(only if DIAGNOSTIC)

The problem turned out to be due to the way LK_DRAIN was (not) handled
in union_lock; it just got passed through to the lock on the upper
vnode (which got marked as decommissioned, instead of that happening
to the union vnode.  When the upper vnode was next locked (typically
when it was released), it went kaboom.
This commit is contained in:
sommerfeld 1999-08-01 00:00:57 +00:00
parent 29469abdbd
commit cb448a064d
2 changed files with 41 additions and 3 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: union.h,v 1.10 1997/05/05 07:14:02 mycroft Exp $ */
/* $NetBSD: union.h,v 1.11 1999/08/01 00:00:57 sommerfeld Exp $ */
/*
* Copyright (c) 1994 The Regents of the University of California.
@ -92,6 +92,8 @@ struct union_node {
#define UN_ULOCK 0x04 /* Upper node is locked */
#define UN_KLOCK 0x08 /* Keep upper node locked on vput */
#define UN_CACHED 0x10 /* In union cache */
#define UN_DRAINING 0x20 /* upper node lock is draining */
#define UN_DRAINED 0x40 /* upper node lock is drained */
extern int union_allocvp __P((struct vnode **, struct mount *,
struct vnode *, struct vnode *,

View File

@ -1,4 +1,4 @@
/* $NetBSD: union_vnops.c,v 1.44 1999/03/25 13:05:42 bouyer Exp $ */
/* $NetBSD: union_vnops.c,v 1.45 1999/08/01 00:00:57 sommerfeld Exp $ */
/*
* Copyright (c) 1992, 1993, 1994, 1995 Jan-Simon Pendry.
@ -1595,7 +1595,9 @@ union_lock(v)
int flags = ap->a_flags;
struct union_node *un;
int error;
#ifdef DIAGNOSTIC
int drain = 0;
#endif
genfs_nolock(ap);
/*
@ -1609,6 +1611,31 @@ union_lock(v)
*/
flags &= ~LK_INTERLOCK;
un = VTOUNION(vp);
#ifdef DIAGNOSTIC
if (un->un_flags & (UN_DRAINING|UN_DRAINED)) {
if (un->un_flags & UN_DRAINED)
panic("union: %p: warning: locking decommissioned lock\n", vp);
if ((flags & LK_TYPE_MASK) != LK_RELEASE)
panic("union: %p: non-release on draining lock: %d\n",
vp, flags & LK_TYPE_MASK);
un->un_flags &= ~UN_DRAINING;
if ((flags & LK_REENABLE) == 0)
un->un_flags |= UN_DRAINED;
}
#endif
/*
* Don't pass DRAIN through to sub-vnode lock; keep track of
* DRAIN state at this level, and just get an exclusive lock
* on the underlying vnode.
*/
if ((flags & LK_TYPE_MASK) == LK_DRAIN) {
#ifdef DIAGNOSTIC
drain = 1;
#endif
flags = LK_EXCLUSIVE | (flags & ~LK_TYPE_MASK);
}
start:
un = VTOUNION(vp);
@ -1633,6 +1660,7 @@ start:
#endif
}
/* XXX ignores LK_NOWAIT */
if (un->un_flags & UN_LOCKED) {
#ifdef DIAGNOSTIC
if (curproc && un->un_pid == curproc->p_pid &&
@ -1649,6 +1677,8 @@ start:
un->un_pid = curproc->p_pid;
else
un->un_pid = -1;
if (drain)
un->un_flags |= UN_DRAINING;
#endif
un->un_flags |= UN_LOCKED;
@ -1682,6 +1712,8 @@ union_unlock(v)
if (curproc && un->un_pid != curproc->p_pid &&
curproc->p_pid > -1 && un->un_pid > -1)
panic("union: unlocking other process's union node");
if (un->un_flags & UN_DRAINED)
panic("union: %p: warning: unlocking decommissioned lock\n", ap->a_vp);
#endif
un->un_flags &= ~UN_LOCKED;
@ -1698,6 +1730,10 @@ union_unlock(v)
#ifdef DIAGNOSTIC
un->un_pid = 0;
if (un->un_flags & UN_DRAINING) {
un->un_flags |= UN_DRAINED;
un->un_flags &= ~UN_DRAINING;
}
#endif
genfs_nounlock(ap);