Fix lock order inversion between vnode locks and ufs_hashlock. Addresses

kern/36331 (MP deadlock between ufs_ihashget() and VOP_LOOKUP()) for ffs,
other file systems to follow. Reported by perseant@, debugged by Sverre
Froyen, patch posted/tested by Blair Sadewitz.
This commit is contained in:
ad 2007-05-28 23:42:56 +00:00
parent 565d4d6ca6
commit 1ae6657a7b
2 changed files with 17 additions and 12 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: ffs_vfsops.c,v 1.199 2007/05/17 07:26:23 hannken Exp $ */
/* $NetBSD: ffs_vfsops.c,v 1.200 2007/05/28 23:42:56 ad Exp $ */
/*
* Copyright (c) 1989, 1991, 1993, 1994
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.199 2007/05/17 07:26:23 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.200 2007/05/28 23:42:56 ad Exp $");
#if defined(_KERNEL_OPT)
#include "opt_ffs.h"
@ -1425,6 +1425,7 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
ump = VFSTOUFS(mp);
dev = ump->um_dev;
retry:
if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
return (0);
@ -1436,15 +1437,15 @@ ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
ip = pool_get(&ffs_inode_pool, PR_WAITOK);
/*
* If someone beat us to it while sleeping in getnewvnode(),
* push back the freshly allocated vnode we don't need, and return.
* If someone beat us to it, put back the freshly allocated
* vnode/inode pair and retry.
*/
mutex_enter(&ufs_hashlock);
if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) {
if (ufs_ihashget(dev, ino, 0) != NULL) {
mutex_exit(&ufs_hashlock);
ungetnewvnode(vp);
pool_put(&ffs_inode_pool, ip);
return (0);
goto retry;
}
vp->v_flag |= VLOCKSWORK;

View File

@ -1,4 +1,4 @@
/* $NetBSD: ufs_ihash.c,v 1.22 2007/02/27 16:11:51 ad Exp $ */
/* $NetBSD: ufs_ihash.c,v 1.23 2007/05/28 23:42:56 ad Exp $ */
/*
* Copyright (c) 1982, 1986, 1989, 1991, 1993
@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: ufs_ihash.c,v 1.22 2007/02/27 16:11:51 ad Exp $");
__KERNEL_RCSID(0, "$NetBSD: ufs_ihash.c,v 1.23 2007/05/28 23:42:56 ad Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -145,10 +145,14 @@ ufs_ihashget(dev_t dev, ino_t inum, int flags)
LIST_FOREACH(ip, ipp, i_hash) {
if (inum == ip->i_number && dev == ip->i_dev) {
vp = ITOV(ip);
simple_lock(&vp->v_interlock);
mutex_exit(&ufs_ihash_lock);
if (vget(vp, flags | LK_INTERLOCK))
goto loop;
if (flags == 0) {
mutex_exit(&ufs_ihash_lock);
} else {
simple_lock(&vp->v_interlock);
mutex_exit(&ufs_ihash_lock);
if (vget(vp, flags | LK_INTERLOCK))
goto loop;
}
return (vp);
}
}