From 9a2b8fca80d97f62401565c1c0a0bbdea354f5be Mon Sep 17 00:00:00 2001 From: Robert Watson Date: Sat, 29 Jan 2000 15:22:58 +0000 Subject: [PATCH] This patch fixes a locking bug that can result in deadlock if the codepath is followed. From the PR: vclean calls vrele leading to deadlock (if usecount > 0) vclean() calls vrele() if v_usecount of the node was higher than one. But before calling it, it sets the VXLOCK flag, which will make vn_lock called from vrele dead-lock. PR: kern/15117 Submitted by: Assar Westerlund Reviewed by: rwatson Obtained from: NetBSD --- sys/kern/vfs_export.c | 19 +++++++++++++++++-- sys/kern/vfs_subr.c | 19 +++++++++++++++++-- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/sys/kern/vfs_export.c b/sys/kern/vfs_export.c index 97d62510b83e..e0ef113e50c1 100644 --- a/sys/kern/vfs_export.c +++ b/sys/kern/vfs_export.c @@ -1701,8 +1701,23 @@ vclean(vp, flags, p) if (VOP_RECLAIM(vp, p)) panic("vclean: cannot reclaim"); - if (active) - vrele(vp); + if (active) { + /* + * Inline copy of vrele() since VOP_INACTIVE + * has already been called. + */ + simple_lock(&vp->v_interlock); + if (--vp->v_usecount <= 0) { +#ifdef DIAGNOSTIC + if (vp->v_usecount < 0 || vp->v_writecount != 0) { + vprint("vclean: bad ref count", vp); + panic("vclean: ref cnt"); + } +#endif + vfree(vp); + } + simple_unlock(&vp->v_interlock); + } cache_purge(vp); if (vp->v_vnlock) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 97d62510b83e..e0ef113e50c1 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1701,8 +1701,23 @@ vclean(vp, flags, p) if (VOP_RECLAIM(vp, p)) panic("vclean: cannot reclaim"); - if (active) - vrele(vp); + if (active) { + /* + * Inline copy of vrele() since VOP_INACTIVE + * has already been called. + */ + simple_lock(&vp->v_interlock); + if (--vp->v_usecount <= 0) { +#ifdef DIAGNOSTIC + if (vp->v_usecount < 0 || vp->v_writecount != 0) { + vprint("vclean: bad ref count", vp); + panic("vclean: ref cnt"); + } +#endif + vfree(vp); + } + simple_unlock(&vp->v_interlock); + } cache_purge(vp); if (vp->v_vnlock) {