diff options
author | dillon <dillon@FreeBSD.org> | 2001-12-20 22:42:27 +0000 |
---|---|---|
committer | dillon <dillon@FreeBSD.org> | 2001-12-20 22:42:27 +0000 |
commit | ac9876d609290ddd585a1e5a67550061f01c20dd (patch) | |
tree | 74464ed2703c6925992ebe509294859864e96118 | |
parent | 53b1a7ecefc98fa3a2e71925a3be359d4873214b (diff) | |
download | FreeBSD-src-ac9876d609290ddd585a1e5a67550061f01c20dd.zip FreeBSD-src-ac9876d609290ddd585a1e5a67550061f01c20dd.tar.gz |
Fix a BUF_TIMELOCK race against BUF_LOCK and fix a deadlock in vget()
against VM_WAIT in the pageout code. Both fixes involve adjusting
the lockmgr's timeout capability so locks obtained with timeouts do not
interfere with locks obtained without a timeout.
Hopefully MFC: before the 4.5 release
-rw-r--r-- | sys/fs/hpfs/hpfs_vfsops.c | 2 | ||||
-rw-r--r-- | sys/fs/msdosfs/msdosfs_denode.c | 2 | ||||
-rw-r--r-- | sys/fs/ntfs/ntfs_vfsops.c | 2 | ||||
-rw-r--r-- | sys/fs/nwfs/nwfs_node.c | 2 | ||||
-rw-r--r-- | sys/fs/smbfs/smbfs_node.c | 2 | ||||
-rw-r--r-- | sys/fs/unionfs/union_subr.c | 2 | ||||
-rw-r--r-- | sys/kern/kern_lock.c | 6 | ||||
-rw-r--r-- | sys/kern/vfs_subr.c | 2 | ||||
-rw-r--r-- | sys/sys/buf.h | 3 | ||||
-rw-r--r-- | sys/sys/lockmgr.h | 3 | ||||
-rw-r--r-- | sys/sys/vnode.h | 5 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 2 | ||||
-rw-r--r-- | sys/ufs/ifs/ifs_vfsops.c | 2 | ||||
-rw-r--r-- | sys/vm/vm_pageout.c | 15 |
14 files changed, 32 insertions, 18 deletions
diff --git a/sys/fs/hpfs/hpfs_vfsops.c b/sys/fs/hpfs/hpfs_vfsops.c index d53d1b6..c3226e6 100644 --- a/sys/fs/hpfs/hpfs_vfsops.c +++ b/sys/fs/hpfs/hpfs_vfsops.c @@ -511,7 +511,7 @@ hpfs_vget( mtx_init(&hp->h_interlock, "hpfsnode interlock", MTX_DEF); - lockinit(&hp->h_lock, PINOD, "hpnode", 0, 0); + lockinit(&hp->h_lock, PINOD, "hpnode", VLKTIMEOUT, 0); hp->h_flag = H_INVAL; hp->h_vp = vp; diff --git a/sys/fs/msdosfs/msdosfs_denode.c b/sys/fs/msdosfs/msdosfs_denode.c index 8ab7f11..9538ba3 100644 --- a/sys/fs/msdosfs/msdosfs_denode.c +++ b/sys/fs/msdosfs/msdosfs_denode.c @@ -261,7 +261,7 @@ deget(pmp, dirclust, diroffset, depp) return error; } bzero((caddr_t)ldep, sizeof *ldep); - lockinit(&nvp->v_lock, PINOD, "denode", 0, 0); + lockinit(&nvp->v_lock, PINOD, "denode", VLKTIMEOUT, 0); nvp->v_vnlock = &nvp->v_lock; nvp->v_data = ldep; ldep->de_vnode = nvp; diff --git a/sys/fs/ntfs/ntfs_vfsops.c b/sys/fs/ntfs/ntfs_vfsops.c index 448f130..2a58601 100644 --- a/sys/fs/ntfs/ntfs_vfsops.c +++ b/sys/fs/ntfs/ntfs_vfsops.c @@ -741,7 +741,7 @@ ntfs_vgetex( } dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino)); - lockinit(&fp->f_lock, PINOD, "fnode", 0, 0); + lockinit(&fp->f_lock, PINOD, "fnode", VLKTIMEOUT, 0); fp->f_vp = vp; vp->v_data = fp; vp->v_type = f_type; diff --git a/sys/fs/nwfs/nwfs_node.c b/sys/fs/nwfs/nwfs_node.c index 8fce6ac..d6f8788 100644 --- a/sys/fs/nwfs/nwfs_node.c +++ b/sys/fs/nwfs/nwfs_node.c @@ -185,7 +185,7 @@ rescan: if (dvp) { np->n_parent = VTONW(dvp)->n_fid; } - lockinit(&vp->v_lock, PINOD, "nwnode", 0, LK_CANRECURSE); + lockinit(&vp->v_lock, PINOD, "nwnode", VLKTIMEOUT, LK_CANRECURSE); lockmgr(&nwhashlock, LK_EXCLUSIVE, NULL, td); /* * Another process can create vnode while we blocked in malloc() or diff --git a/sys/fs/smbfs/smbfs_node.c b/sys/fs/smbfs/smbfs_node.c index 9fa3db8..f170b1d 100644 --- a/sys/fs/smbfs/smbfs_node.c +++ b/sys/fs/smbfs/smbfs_node.c @@ -243,7 +243,7 @@ loop: } else if (vp->v_type == VREG) SMBERROR("new vnode '%s' born without parent ?\n", np->n_name); - lockinit(&vp->v_lock, PINOD, "smbnode", 0, LK_CANRECURSE); + lockinit(&vp->v_lock, PINOD, "smbnode", VLKTIMEOUT, LK_CANRECURSE); vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); smbfs_hash_lock(smp, td); diff --git a/sys/fs/unionfs/union_subr.c b/sys/fs/unionfs/union_subr.c index 5919672..8320f4a 100644 --- a/sys/fs/unionfs/union_subr.c +++ b/sys/fs/unionfs/union_subr.c @@ -572,7 +572,7 @@ loop: un = VTOUNION(*vpp); bzero(un, sizeof(*un)); - lockinit(&un->un_lock, PVFS, "unlock", 0, 0); + lockinit(&un->un_lock, PVFS, "unlock", VLKTIMEOUT, 0); vn_lock(*vpp, LK_EXCLUSIVE | LK_RETRY, td); un->un_vnode = *vpp; diff --git a/sys/kern/kern_lock.c b/sys/kern/kern_lock.c index c7d4f24..929be46 100644 --- a/sys/kern/kern_lock.c +++ b/sys/kern/kern_lock.c @@ -166,7 +166,8 @@ acquire(struct lock *lkp, int extflags, int wanted) { lkp->lk_flags |= LK_WAIT_NONZERO; lkp->lk_waitcount++; error = msleep(lkp, lkp->lk_interlock, lkp->lk_prio, - lkp->lk_wmesg, lkp->lk_timo); + lkp->lk_wmesg, + ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); if (lkp->lk_waitcount == 1) { lkp->lk_flags &= ~LK_WAIT_NONZERO; lkp->lk_waitcount = 0; @@ -469,7 +470,8 @@ acquiredrain(struct lock *lkp, int extflags) { while (lkp->lk_flags & LK_ALL) { lkp->lk_flags |= LK_WAITDRAIN; error = msleep(&lkp->lk_flags, lkp->lk_interlock, lkp->lk_prio, - lkp->lk_wmesg, lkp->lk_timo); + lkp->lk_wmesg, + ((extflags & LK_TIMELOCK) ? lkp->lk_timo : 0)); if (error) return error; if (extflags & LK_SLEEPFAIL) { diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index d5dd6aa..7ccad17 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -793,7 +793,7 @@ getnewvnode(tag, mp, vops, vpp) vp->v_type = VNON; vp->v_tag = tag; vp->v_op = vops; - lockinit(&vp->v_lock, PVFS, "vnlock", 0, LK_NOPAUSE); + lockinit(&vp->v_lock, PVFS, "vnlock", VLKTIMEOUT, LK_NOPAUSE); insmntque(vp, mp); *vpp = vp; vp->v_usecount = 1; diff --git a/sys/sys/buf.h b/sys/sys/buf.h index efeaec1..051a323 100644 --- a/sys/sys/buf.h +++ b/sys/sys/buf.h @@ -279,7 +279,6 @@ BUF_LOCK(struct buf *bp, int locktype) locktype |= LK_INTERLOCK; bp->b_lock.lk_wmesg = buf_wmesg; bp->b_lock.lk_prio = PRIBIO + 4; - bp->b_lock.lk_timo = 0; ret = lockmgr(&(bp)->b_lock, locktype, &buftimelock, curthread); splx(s); return ret; @@ -295,7 +294,7 @@ BUF_TIMELOCK(struct buf *bp, int locktype, char *wmesg, int catch, int timo) s = splbio(); mtx_lock(&buftimelock); - locktype |= LK_INTERLOCK; + locktype |= LK_INTERLOCK | LK_TIMELOCK; bp->b_lock.lk_wmesg = wmesg; bp->b_lock.lk_prio = (PRIBIO + 4) | catch; bp->b_lock.lk_timo = timo; diff --git a/sys/sys/lockmgr.h b/sys/sys/lockmgr.h index 0b4ca9d..e941110 100644 --- a/sys/sys/lockmgr.h +++ b/sys/sys/lockmgr.h @@ -115,12 +115,13 @@ struct lock { * or passed in as arguments to the lock manager. The LK_REENABLE flag may be * set only at the release of a lock obtained by drain. */ -#define LK_EXTFLG_MASK 0x01000070 /* mask of external flags */ +#define LK_EXTFLG_MASK 0x03000070 /* mask of external flags */ #define LK_NOWAIT 0x00000010 /* do not sleep to await lock */ #define LK_SLEEPFAIL 0x00000020 /* sleep, then return failure */ #define LK_CANRECURSE 0x00000040 /* allow recursive exclusive lock */ #define LK_REENABLE 0x00000080 /* lock is be reenabled after drain */ #define LK_NOPAUSE 0x01000000 /* no spinloop */ +#define LK_TIMELOCK 0x02000000 /* use lk_timo, else no timeout */ /* * Internal lock flags. * diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h index bcf5a84..6ea6ea6 100644 --- a/sys/sys/vnode.h +++ b/sys/sys/vnode.h @@ -240,6 +240,11 @@ struct vattr { */ #define VNOVAL (-1) +/* + * LK_TIMELOCK timeout for vnode locks (used mainly by the pageout daemon) + */ +#define VLKTIMEOUT (hz / 20 + 1) + #ifdef _KERNEL #ifdef MALLOC_DECLARE diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index d6bc8b1..a9985d5 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1186,7 +1186,7 @@ restart: * FFS supports lock sharing in the stack of vnodes */ vp->v_vnlock = &vp->v_lock; - lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE); + lockinit(vp->v_vnlock, PINOD, "inode", VLKTIMEOUT, LK_CANRECURSE); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; diff --git a/sys/ufs/ifs/ifs_vfsops.c b/sys/ufs/ifs/ifs_vfsops.c index 0cbf5d0..7eade14 100644 --- a/sys/ufs/ifs/ifs_vfsops.c +++ b/sys/ufs/ifs/ifs_vfsops.c @@ -221,7 +221,7 @@ restart: * IFS supports lock sharing in the stack of vnodes */ vp->v_vnlock = &vp->v_lock; - lockinit(vp->v_vnlock, PINOD, "inode", 0, LK_CANRECURSE); + lockinit(vp->v_vnlock, PINOD, "inode", VLKTIMEOUT, LK_CANRECURSE); vp->v_data = ip; ip->i_vnode = vp; ip->i_fs = fs = ump->um_fs; diff --git a/sys/vm/vm_pageout.c b/sys/vm/vm_pageout.c index 73ef06d..47ce9e8 100644 --- a/sys/vm/vm_pageout.c +++ b/sys/vm/vm_pageout.c @@ -193,6 +193,10 @@ SYSCTL_INT(_vm, OID_AUTO, defer_swapspace_pageouts, SYSCTL_INT(_vm, OID_AUTO, disable_swapspace_pageouts, CTLFLAG_RW, &disable_swap_pageouts, 0, "Disallow swapout of dirty pages"); +static int pageout_lock_miss; +SYSCTL_INT(_vm, OID_AUTO, pageout_lock_miss, + CTLFLAG_RD, &pageout_lock_miss, 0, "vget() lock misses during pageout"); + #define VM_PAGEOUT_PAGE_COUNT 16 int vm_pageout_page_count = VM_PAGEOUT_PAGE_COUNT; @@ -860,17 +864,20 @@ rescan0: * way too large a weighting to defering the freeing * of dirty pages. * - * XXX we need to be able to apply a timeout to the - * vget() lock attempt. + * We can't wait forever for the vnode lock, we might + * deadlock due to a vn_read() getting stuck in + * vm_wait while holding this vnode. We skip the + * vnode if we can't get it in a reasonable amount + * of time. */ - if (object->type == OBJT_VNODE) { vp = object->handle; mp = NULL; if (vp->v_type == VREG) vn_start_write(vp, &mp, V_NOWAIT); - if (vget(vp, LK_EXCLUSIVE|LK_NOOBJ, curthread)) { + if (vget(vp, LK_EXCLUSIVE|LK_NOOBJ|LK_TIMELOCK, curthread)) { + ++pageout_lock_miss; vn_finished_write(mp); if (object->flags & OBJ_MIGHTBEDIRTY) vnodes_skipped++; |