From b0911300ee0f72264351f0442bd32f63d280bd3a Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 28 Dec 2009 09:15:25 -0800 Subject: [PATCH] kernel - MPSAFE stabilization * Fix for 'panic: sysref_activate: bad count 00000002'. Mistakenly assumed the lockmgr lock was sufficient protection but forgot it might be acquired LK_SHARED. Extend v_spinlock protection to fix the problem. --- sys/kern/kern_sysref.c | 2 ++ sys/kern/vfs_lock.c | 11 ++++++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_sysref.c b/sys/kern/kern_sysref.c index 93b84fd..705dac3 100644 --- a/sys/kern/kern_sysref.c +++ b/sys/kern/kern_sysref.c @@ -266,6 +266,8 @@ sysref_dtor(void *data, void *privdata) * so -0x40000000 (during initialization) will translate to a ref count of 1. * Any references made during initialization will translate to additional * positive ref counts. + * + * MPSAFE */ void sysref_activate(struct sysref *sr) diff --git a/sys/kern/vfs_lock.c b/sys/kern/vfs_lock.c index 0c8852a..2731b54 100644 --- a/sys/kern/vfs_lock.c +++ b/sys/kern/vfs_lock.c @@ -453,6 +453,9 @@ vget(struct vnode *vp, int flags) * Reference the structure and then acquire the lock. 0->1 * transitions and refs during termination are allowed here so * call sysref directly. + * + * NOTE: The requested lock might be a shared lock and does + * not protect our access to the refcnt or other fields. */ sysref_get(&vp->v_sysref); if ((error = vn_lock(vp, flags)) != 0) { @@ -477,25 +480,27 @@ vget(struct vnode *vp, int flags) * In the VFREE/VCACHED case we have to throw away the * sysref that was earmarking those cases and preventing * the vnode from being destroyed. Our sysref is still held. + * + * The spinlock is our only real protection here. */ spin_lock_wr(&vp->v_spinlock); if (vp->v_flag & VFREE) { __vbusy(vp); + sysref_activate(&vp->v_sysref); spin_unlock_wr(&vp->v_spinlock); sysref_put(&vp->v_sysref); - sysref_activate(&vp->v_sysref); } else if (vp->v_flag & VCACHED) { _vclrflags(vp, VCACHED); + sysref_activate(&vp->v_sysref); spin_unlock_wr(&vp->v_spinlock); sysref_put(&vp->v_sysref); - sysref_activate(&vp->v_sysref); } else { - spin_unlock_wr(&vp->v_spinlock); if (sysref_isinactive(&vp->v_sysref)) { sysref_activate(&vp->v_sysref); kprintf("Warning vp %p reactivation race\n", vp); } + spin_unlock_wr(&vp->v_spinlock); } _vclrflags(vp, VINACTIVE); error = 0; -- 1.7.7.2