Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src/sys/ufs/lfs Fix some locking issues that appeared with the s...
details: https://anonhg.NetBSD.org/src/rev/dbf2612a09da
branches: trunk
changeset: 580039:dbf2612a09da
user: perseant <perseant%NetBSD.org@localhost>
date: Wed Apr 06 04:30:46 2005 +0000
description:
Fix some locking issues that appeared with the simple_lock work.
Address a "pager_map" deadlock in lfs_putpages().
diffstat:
sys/ufs/lfs/lfs_bio.c | 27 ++++++++++++-----
sys/ufs/lfs/lfs_vfsops.c | 75 ++++++++++++++++++++++++++++++++++++++++-------
2 files changed, 83 insertions(+), 19 deletions(-)
diffs (247 lines):
diff -r d6f5980514bf -r dbf2612a09da sys/ufs/lfs/lfs_bio.c
--- a/sys/ufs/lfs/lfs_bio.c Wed Apr 06 02:38:17 2005 +0000
+++ b/sys/ufs/lfs/lfs_bio.c Wed Apr 06 04:30:46 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_bio.c,v 1.82 2005/04/01 21:59:46 perseant Exp $ */
+/* $NetBSD: lfs_bio.c,v 1.83 2005/04/06 04:30:46 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.82 2005/04/01 21:59:46 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_bio.c,v 1.83 2005/04/06 04:30:46 perseant Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -546,14 +546,15 @@
* XXX need to think more about the multiple filesystem case.
*
* Called and return with lfs_subsys_lock held.
+ * If fs != NULL, we hold the segment lock for fs.
*/
void
lfs_flush(struct lfs *fs, int flags, int only_onefs)
{
extern u_int64_t locked_fakequeue_count;
struct mount *mp, *nmp;
+ struct lfs *tfs;
- ASSERT_NO_SEGLOCK(fs);
LOCK_ASSERT(simple_lock_held(&lfs_subsys_lock));
KDASSERT(fs == NULL || !LFS_SEGLOCK_HELD(fs));
@@ -572,9 +573,13 @@
simple_unlock(&lfs_subsys_lock);
if (only_onefs) {
- if (vfs_busy(fs->lfs_ivnode->v_mount, LK_NOWAIT, &mountlist_slock))
+ KASSERT(fs != NULL);
+ if (vfs_busy(fs->lfs_ivnode->v_mount, LK_NOWAIT,
+ &mountlist_slock))
goto errout;
+ simple_lock(&fs->lfs_interlock);
lfs_flush_fs(fs, flags);
+ simple_unlock(&fs->lfs_interlock);
vfs_unbusy(fs->lfs_ivnode->v_mount);
} else {
locked_fakequeue_count = 0;
@@ -587,8 +592,12 @@
continue;
}
if (strncmp(&mp->mnt_stat.f_fstypename[0], MOUNT_LFS,
- MFSNAMELEN) == 0)
- lfs_flush_fs(VFSTOUFS(mp)->um_lfs, flags);
+ MFSNAMELEN) == 0) {
+ tfs = VFSTOUFS(mp)->um_lfs;
+ simple_lock(&tfs->lfs_interlock);
+ lfs_flush_fs(tfs, flags);
+ simple_unlock(&tfs->lfs_interlock);
+ }
simple_lock(&mountlist_slock);
nmp = CIRCLEQ_NEXT(mp, mnt_list);
vfs_unbusy(mp);
@@ -681,6 +690,7 @@
locked_queue_bytes + INOBYTES(fs) > LFS_MAX_BYTES ||
lfs_subsys_pages > LFS_MAX_PAGES ||
lfs_dirvcount > LFS_MAX_DIROP || fs->lfs_diropwait > 0) {
+ simple_unlock(&fs->lfs_interlock);
lfs_flush(fs, flags, 0);
} else if (lfs_fs_pagetrip && fs->lfs_pages > lfs_fs_pagetrip) {
/*
@@ -689,7 +699,9 @@
*/
++fs->lfs_pdflush;
wakeup(&lfs_writer_daemon);
- }
+ simple_unlock(&fs->lfs_interlock);
+ } else
+ simple_unlock(&fs->lfs_interlock);
while (locked_queue_count + INOCOUNT(fs) > LFS_WAIT_BUFS ||
locked_queue_bytes + INOBYTES(fs) > LFS_WAIT_BYTES ||
@@ -717,7 +729,6 @@
}
}
simple_unlock(&lfs_subsys_lock);
- simple_unlock(&fs->lfs_interlock);
return (error);
}
diff -r d6f5980514bf -r dbf2612a09da sys/ufs/lfs/lfs_vfsops.c
--- a/sys/ufs/lfs/lfs_vfsops.c Wed Apr 06 02:38:17 2005 +0000
+++ b/sys/ufs/lfs/lfs_vfsops.c Wed Apr 06 04:30:46 2005 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: lfs_vfsops.c,v 1.169 2005/04/01 21:59:46 perseant Exp $ */
+/* $NetBSD: lfs_vfsops.c,v 1.170 2005/04/06 04:30:46 perseant Exp $ */
/*-
* Copyright (c) 1999, 2000, 2001, 2002, 2003 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.169 2005/04/01 21:59:46 perseant Exp $");
+__KERNEL_RCSID(0, "$NetBSD: lfs_vfsops.c,v 1.170 2005/04/06 04:30:46 perseant Exp $");
#if defined(_KERNEL_OPT)
#include "opt_quota.h"
@@ -127,6 +127,11 @@
extern const struct vnodeopv_desc lfs_specop_opv_desc;
extern const struct vnodeopv_desc lfs_fifoop_opv_desc;
+/* From uvm/uvm_pager.c */
+extern struct vm_map *pager_map;
+extern struct simplelock pager_map_wanted_lock;
+extern boolean_t pager_map_wanted;
+
pid_t lfs_writer_daemon = 0;
int lfs_do_flush = 0;
int lfs_do_rfw = 0;
@@ -190,6 +195,7 @@
{
struct mount *mp, *nmp;
struct lfs *fs;
+ int loopcount;
lfs_writer_daemon = curproc->p_pid;
@@ -232,6 +238,7 @@
* If global state wants a flush, flush everything.
*/
simple_lock(&lfs_subsys_lock);
+ loopcount = 0;
while (lfs_do_flush || locked_queue_count > LFS_MAX_BUFS ||
locked_queue_bytes > LFS_MAX_BYTES ||
lfs_subsys_pages > LFS_MAX_PAGES) {
@@ -250,6 +257,19 @@
lfs_flush(NULL, SEGM_WRITERD, 0);
lfs_do_flush = 0;
+ if (++loopcount > 10) {
+ printf("lfs_writer_daemon: livelock: "
+ "lqc = %lld (of %lld), "
+ "lqb = %lld (of %lld), "
+ "lsp = %lld (of %lld)\n",
+ (long long)locked_queue_count,
+ (long long)LFS_MAX_BUFS,
+ (long long)locked_queue_bytes,
+ (long long)LFS_MAX_BYTES,
+ (long long)lfs_subsys_pages,
+ (long long)LFS_MAX_PAGES);
+ break;
+ }
}
}
/* NOTREACHED */
@@ -1919,7 +1939,7 @@
int i, s, error, run;
int fs_bshift;
vaddr_t kva;
- off_t eof, offset, startoffset;
+ off_t eof, offset, startoffset = 0;
size_t bytes, iobytes, skipbytes;
daddr_t lbn, blkno;
struct vm_page *pg;
@@ -1969,13 +1989,13 @@
error = 0;
pg = pgs[0];
startoffset = pg->offset;
- bytes = MIN(npages << PAGE_SHIFT, eof - startoffset);
+ if (startoffset >= eof) {
+ goto tryagain;
+ } else
+ bytes = MIN(npages << PAGE_SHIFT, eof - startoffset);
skipbytes = 0;
- /* KASSERT(bytes != 0); */
- if (bytes == 0)
- DLOG((DLOG_PAGE, "lfs_gop_write: ino %d bytes == 0 offset %"
- PRId64 "\n", VTOI(vp)->i_number, pgs[0]->offset));
+ KASSERT(bytes != 0);
/* Swap PG_DELWRI for PG_PAGEOUT */
for (i = 0; i < npages; i++)
@@ -2005,10 +2025,38 @@
}
/*
- * XXX We can deadlock here on pager_map with UVMPAGER_MAPIN_WAITOK.
+ * We could deadlock here on pager_map with UVMPAGER_MAPIN_WAITOK.
+ * If we would, write what we have and try again. If we don't
+ * have anything to write, we'll have to sleep.
*/
- kva = uvm_pagermapin(pgs, npages,
- UVMPAGER_MAPIN_WRITE | UVMPAGER_MAPIN_WAITOK);
+ while ((kva = uvm_pagermapin(pgs, npages, UVMPAGER_MAPIN_WRITE |
+ (((SEGSUM *)(sp->segsum))->ss_nfinfo < 1 ?
+ UVMPAGER_MAPIN_WAITOK : 0))) == 0x0) {
+ int version;
+
+ DLOG((DLOG_PAGE, "lfs_gop_write: forcing write\n"));
+ simple_lock(&pager_map_wanted_lock);
+ pager_map_wanted = TRUE;
+ simple_unlock(&pager_map_wanted_lock);
+ lfs_updatemeta(sp);
+
+ version = sp->fip->fi_version;
+ (void) lfs_writeseg(fs, sp);
+
+ sp->fip->fi_version = version;
+ sp->fip->fi_ino = ip->i_number;
+ /* Add the current file to the segment summary. */
+ ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
+ sp->sum_bytes_left -= FINFOSIZE;
+
+ simple_lock(&pager_map_wanted_lock);
+ if (pager_map_wanted == TRUE) {
+ UVMHIST_LOG(maphist, " SLEEPING on pager_map",0,0,0,0);
+ UVM_UNLOCK_AND_WAIT(pager_map, &pager_map_wanted_lock,
+ FALSE, "pager_map", 0);
+ } else
+ simple_unlock(&pager_map_wanted_lock);
+ }
s = splbio();
simple_lock(&global_v_numoutput_slock);
@@ -2144,6 +2192,10 @@
DLOG((DLOG_PAGE, "lfs_gop_write: clean pages dirtied\n"));
else if ((pgs[0]->offset & fs->lfs_bmask) != 0)
DLOG((DLOG_PAGE, "lfs_gop_write: not on block boundary\n"));
+ else if (startoffset >= eof)
+ DLOG((DLOG_PAGE, "lfs_gop_write: ino %d start 0x%" PRIx64
+ " eof 0x%" PRIx64 " npages=%d\n", VTOI(vp)->i_number,
+ pgs[0]->offset, eof, npages));
else
DLOG((DLOG_PAGE, "lfs_gop_write: seglock not held\n"));
@@ -2158,6 +2210,7 @@
}
uvm_pageactivate(pg);
pg->flags &= ~(PG_CLEAN|PG_DELWRI|PG_PAGEOUT|PG_RELEASED);
+ DLOG((DLOG_PAGE, "pg[%d] = %p\n", i, pg));
DLOG((DLOG_PAGE, "pg[%d]->flags = %x\n", i, pg->flags));
DLOG((DLOG_PAGE, "pg[%d]->pqflags = %x\n", i, pg->pqflags));
DLOG((DLOG_PAGE, "pg[%d]->uanon = %p\n", i, pg->uanon));
Home |
Main Index |
Thread Index |
Old Index