From 298693f7a0177ad2291be7a6c52371fb311b4a17 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Thu, 14 Jan 2010 21:51:45 -0800 Subject: [PATCH] kernel - Fix not-quite-nonblocking VX lock in allocfreevnode() * Introduce LK_NOSPINWAIT to tell lockmgr() to not even spin on the spinlock if it can't get it immediately. * There is a lock order reversal between vfs_spin and vp->v_spinlock where vx_lock_nonblock() can deadlock in allocfreevnode(). Normally I'd vhold() the vnode but the freelist code is rather fragile and I don't want to have to vdrop() later on. So instead use LK_NOSPINWAIT to avoid the situation. * This is a hack. --- sys/kern/kern_lock.c | 9 ++++++++- sys/kern/vfs_lock.c | 7 ++++++- sys/sys/lock.h | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index f73b2399e0..d49876a7d3 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -204,7 +204,14 @@ debuglockmgr(struct lock *lkp, u_int flags, #endif } - spin_lock_wr(&lkp->lk_spinlock); + /* + * So sue me, I'm too tired. + */ + if (spin_trylock_wr(&lkp->lk_spinlock) == FALSE) { + if (flags & LK_NOSPINWAIT) + return(EBUSY); + spin_lock_wr(&lkp->lk_spinlock); + } extflags = (flags | lkp->lk_flags) & LK_EXTFLG_MASK; td = curthread; diff --git a/sys/kern/vfs_lock.c b/sys/kern/vfs_lock.c index 36fb12b3c2..bcc36e24e3 100644 --- a/sys/kern/vfs_lock.c +++ b/sys/kern/vfs_lock.c @@ -440,7 +440,7 @@ vx_lock(struct vnode *vp) static int vx_lock_nonblock(struct vnode *vp) { - return(lockmgr(&vp->v_lock, LK_EXCLUSIVE | LK_NOWAIT)); + return(lockmgr(&vp->v_lock, LK_EXCLUSIVE | LK_NOWAIT | LK_NOSPINWAIT)); } void @@ -618,6 +618,11 @@ allocfreevnode(void) /* * Try to lock the first vnode on the free list. * Cycle if we can't. + * + * We use a bad hack in vx_lock_nonblock() which avoids + * the lock order reversal between vfs_spin and v_spinlock. + * This is very fragile code and I don't want to use + * vhold here. */ spin_lock_wr(&vfs_spin); vp = TAILQ_FIRST(&vnode_free_list); diff --git a/sys/sys/lock.h b/sys/sys/lock.h index 2e1288780e..a2b196db61 100644 --- a/sys/sys/lock.h +++ b/sys/sys/lock.h @@ -131,7 +131,7 @@ struct lock { #define LK_SLEEPFAIL 0x00000020 /* sleep, then return failure */ #define LK_CANRECURSE 0x00000040 /* allow recursive exclusive lock */ #define LK_UNUSED0080 0x00000080 -#define LK_UNUSED1000000 0x01000000 +#define LK_NOSPINWAIT 0x01000000 /* don't wait for spinlock */ #define LK_TIMELOCK 0x02000000 #define LK_PCATCH 0x04000000 /* timelocked with signal catching */ /* -- 2.11.4.GIT