diff --git a/sys/kern/vfs_bio.c b/sys/kern/vfs_bio.c index 34f7acb..1fb0581 100644 --- a/sys/kern/vfs_bio.c +++ b/sys/kern/vfs_bio.c @@ -398,6 +398,8 @@ bufcountwakeup(struct buf *bp) KASSERT((bp->b_vflags & BV_INFREECNT) == 0, ("buf %p already counted as free", bp)); + if (bp->b_bufobj != NULL) + mtx_assert(BO_MTX(bp->b_bufobj), MA_OWNED); bp->b_vflags |= BV_INFREECNT; old = atomic_fetchadd_int(&numfreebuffers, 1); KASSERT(old >= 0 && old < nbuf, @@ -711,6 +713,8 @@ bremfree(struct buf *bp) if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0) { KASSERT((bp->b_vflags & BV_INFREECNT) != 0, ("buf %p not counted in numfreebuffers", bp)); + if (bp->b_bufobj != NULL) + mtx_assert(BO_MTX(bp->b_bufobj), MA_OWNED); bp->b_vflags &= ~BV_INFREECNT; old = atomic_fetchadd_int(&numfreebuffers, -1); KASSERT(old > 0, ("numfreebuffers dropped to %d", old - 1)); @@ -767,6 +771,8 @@ bremfreel(struct buf *bp) if ((bp->b_flags & B_INVAL) || (bp->b_flags & B_DELWRI) == 0) { KASSERT((bp->b_vflags & BV_INFREECNT) != 0, ("buf %p not counted in numfreebuffers", bp)); + if (bp->b_bufobj != NULL) + mtx_assert(BO_MTX(bp->b_bufobj), MA_OWNED); bp->b_vflags &= ~BV_INFREECNT; old = atomic_fetchadd_int(&numfreebuffers, -1); KASSERT(old > 0, ("numfreebuffers dropped to %d", old - 1)); @@ -1409,8 +1415,16 @@ brelse(struct buf *bp) /* enqueue */ mtx_lock(&bqlock); /* Handle delayed bremfree() processing. */ - if (bp->b_flags & B_REMFREE) + if (bp->b_flags & B_REMFREE) { + struct bufobj *bo; + + bo = bp->b_bufobj; + if (bo != NULL) + BO_LOCK(bo); bremfreel(bp); + if (bo != NULL) + BO_UNLOCK(bo); + } if (bp->b_qindex != QUEUE_NONE) panic("brelse: free buffer onto another queue???"); @@ -1471,8 +1485,16 @@ brelse(struct buf *bp) * if B_INVAL is set ). */ - if (!(bp->b_flags & B_DELWRI)) + if (!(bp->b_flags & B_DELWRI)) { + struct bufobj *bo; + + bo = bp->b_bufobj; + if (bo != NULL) + BO_LOCK(bo); bufcountwakeup(bp); + if (bo != NULL) + BO_UNLOCK(bo); + } /* * Something we can maybe free or reuse @@ -1501,6 +1523,8 @@ brelse(struct buf *bp) void bqrelse(struct buf *bp) { + struct bufobj *bo; + CTR3(KTR_BUF, "bqrelse(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags); KASSERT(!(bp->b_flags & (B_CLUSTER|B_PAGING)), ("bqrelse: inappropriate B_PAGING or B_CLUSTER bp %p", bp)); @@ -1511,10 +1535,15 @@ bqrelse(struct buf *bp) return; } + bo = bp->b_bufobj; if (bp->b_flags & B_MANAGED) { if (bp->b_flags & B_REMFREE) { mtx_lock(&bqlock); + if (bo != NULL) + BO_LOCK(bo); bremfreel(bp); + if (bo != NULL) + BO_UNLOCK(bo); mtx_unlock(&bqlock); } bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF); @@ -1524,8 +1553,13 @@ bqrelse(struct buf *bp) mtx_lock(&bqlock); /* Handle delayed bremfree() processing. */ - if (bp->b_flags & B_REMFREE) + if (bp->b_flags & B_REMFREE) { + if (bo != NULL) + BO_LOCK(bo); bremfreel(bp); + if (bo != NULL) + BO_UNLOCK(bo); + } if (bp->b_qindex != QUEUE_NONE) panic("bqrelse: free buffer onto another queue???"); /* buffers with stale but valid contents */ @@ -1560,8 +1594,13 @@ bqrelse(struct buf *bp) } mtx_unlock(&bqlock); - if ((bp->b_flags & B_INVAL) || !(bp->b_flags & B_DELWRI)) + if ((bp->b_flags & B_INVAL) || !(bp->b_flags & B_DELWRI)) { + if (bo != NULL) + BO_LOCK(bo); bufcountwakeup(bp); + if (bo != NULL) + BO_UNLOCK(bo); + } /* * Something we can maybe free or reuse. @@ -1895,7 +1934,11 @@ restart: KASSERT((bp->b_flags & B_DELWRI) == 0, ("delwri buffer %p found in queue %d", bp, qindex)); + if (bp->b_bufobj != NULL) + BO_LOCK(bp->b_bufobj); bremfreel(bp); + if (bp->b_bufobj != NULL) + BO_UNLOCK(bp->b_bufobj); mtx_unlock(&bqlock); if (qindex == QUEUE_CLEAN) { @@ -2632,7 +2675,9 @@ loop: bp->b_flags &= ~B_CACHE; else if ((bp->b_flags & (B_VMIO | B_INVAL)) == 0) bp->b_flags |= B_CACHE; + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); /* * check for size inconsistancies for non-VMIO case. diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index 20982c6..985d73b 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -1260,13 +1260,17 @@ flushbuflist( struct bufv *bufv, int flags, struct bufobj *bo, int slpflag, */ if (((bp->b_flags & (B_DELWRI | B_INVAL)) == B_DELWRI) && (flags & V_SAVE)) { + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); bp->b_flags |= B_ASYNC; bwrite(bp); BO_LOCK(bo); return (EAGAIN); /* XXX: why not loop ? */ } + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); @@ -1318,7 +1322,9 @@ restart: BO_MTX(bo)) == ENOLCK) goto restart; + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); @@ -1340,7 +1346,9 @@ restart: LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, BO_MTX(bo)) == ENOLCK) goto restart; + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); bp->b_flags |= (B_INVAL | B_RELBUF); bp->b_flags &= ~B_ASYNC; brelse(bp); @@ -1372,7 +1380,9 @@ restartsync: VNASSERT((bp->b_flags & B_DELWRI), vp, ("buf(%p) on dirty queue without DELWRI", bp)); + BO_LOCK(bo); bremfree(bp); + BO_UNLOCK(bo); bawrite(bp); BO_LOCK(bo); goto restartsync; diff --git a/sys/ufs/ffs/ffs_softdep.c b/sys/ufs/ffs/ffs_softdep.c index 1977d60..5da0f20 100644 --- a/sys/ufs/ffs/ffs_softdep.c +++ b/sys/ufs/ffs/ffs_softdep.c @@ -857,6 +857,7 @@ static int journal_mount(struct mount *, struct fs *, struct ucred *); static void journal_unmount(struct mount *); static int journal_space(struct ufsmount *, int); static void journal_suspend(struct ufsmount *); +static int journal_unsuspend(struct ufsmount *ump); static void softdep_prelink(struct vnode *, struct vnode *); static void add_to_journal(struct worklist *); static void remove_from_journal(struct worklist *); @@ -1390,6 +1391,8 @@ softdep_process_worklist(mp, full) if (!full && starttime != time_second) break; } + if (full == 0) + journal_unsuspend(ump); FREE_LOCK(&lk); return (matchcnt); } @@ -2436,6 +2439,27 @@ journal_suspend(ump) MNT_IUNLOCK(mp); } +static int +journal_unsuspend(struct ufsmount *ump) +{ + struct jblocks *jblocks; + struct mount *mp; + + mp = UFSTOVFS(ump); + jblocks = ump->softdep_jblocks; + + if (jblocks != NULL && jblocks->jb_suspended && + journal_space(ump, jblocks->jb_min)) { + jblocks->jb_suspended = 0; + FREE_LOCK(&lk); + mp->mnt_susp_owner = curthread; + vfs_write_resume(mp); + ACQUIRE_LOCK(&lk); + return (1); + } + return (0); +} + /* * Called before any allocation function to be certain that there is * sufficient space in the journal prior to creating any new records. @@ -2852,15 +2876,9 @@ softdep_process_journal(mp, flags) * space either try to sync it here to make some progress or * unsuspend it if we already have. */ - if (flags == 0 && jblocks && jblocks->jb_suspended) { - if (journal_space(ump, jblocks->jb_min)) { - FREE_LOCK(&lk); - jblocks->jb_suspended = 0; - mp->mnt_susp_owner = curthread; - vfs_write_resume(mp); - ACQUIRE_LOCK(&lk); + if (flags == 0 && jblocks->jb_suspended) { + if (journal_unsuspend(ump)) return; - } FREE_LOCK(&lk); VFS_SYNC(mp, MNT_NOWAIT); ffs_sbupdate(ump, MNT_WAIT, 0); @@ -6030,6 +6048,7 @@ indir_trunc(freework, dbn, lbn) struct jnewblk *jnewblk; struct freeblks *freeblks; struct buf *bp; + struct bufobj *bo; struct fs *fs; struct worklist *wkn; struct worklist *wk; @@ -6070,14 +6089,13 @@ indir_trunc(freework, dbn, lbn) * a complete copy of the indirect block in memory for our use. * Otherwise we have to read the blocks in from the disk. */ -#ifdef notyet - bp = getblk(freeblks->fb_devvp, dbn, (int)fs->fs_bsize, 0, 0, - GB_NOCREAT); -#else - bp = incore(&freeblks->fb_devvp->v_bufobj, dbn); -#endif + bo = &freeblks->fb_devvp->v_bufobj; +check_incore: ACQUIRE_LOCK(&lk); + BO_LOCK(bo); + bp = gbincore(bo, dbn); if (bp != NULL && (wk = LIST_FIRST(&bp->b_dep)) != NULL) { + BO_UNLOCK(bo); if (wk->wk_type != D_INDIRDEP || (wk->wk_state & GOINGAWAY) == 0) panic("indir_trunc: lost indirdep %p", wk); @@ -6090,15 +6108,34 @@ indir_trunc(freework, dbn, lbn) ump->um_numindirdeps -= 1; FREE_LOCK(&lk); } else { -#ifdef notyet - if (bp) - brelse(bp); -#endif FREE_LOCK(&lk); - if (bread(freeblks->fb_devvp, dbn, (int)fs->fs_bsize, - NOCRED, &bp) != 0) { - brelse(bp); - return; + if (bp != NULL) { + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | + LK_INTERLOCK, BO_MTX(bo)) != 0) { + pause("INDIRT", 1); + goto check_incore; + } + } else { + BO_UNLOCK(bo); + bp = getblk(freeblks->fb_devvp, dbn, fs->fs_bsize, 0, + 0, 0); + if (LIST_FIRST(&bp->b_dep) != NULL) { + brelse(bp); + goto check_incore; + } + } + + if ((bp->b_flags & B_CACHE) == 0) { + bp->b_iocmd = BIO_READ; + bp->b_flags &= ~B_INVAL; + bp->b_ioflags &= ~BIO_ERROR; + vfs_busy_pages(bp, 0); + bp->b_iooffset = dbtob(bp->b_blkno); + bstrategy(bp); + if (bufwait(bp) != 0) { + brelse(bp); + return; + } } } /* diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index c099732..6b168f2 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -1820,6 +1820,8 @@ ffs_backgroundwritedone(struct buf *bp) */ KASSERT((origbp->b_vflags & BV_BKGRDINPROG), ("backgroundwritedone: lost buffer2")); + KASSERT(origbp->b_fsprivate3 == bp, ("backgroundwritedone: orphaned")); + origbp->b_fsprivate3 = NULL; origbp->b_vflags &= ~BV_BKGRDINPROG; if (origbp->b_vflags & BV_BKGRDWAIT) { origbp->b_vflags &= ~BV_BKGRDWAIT; @@ -1864,6 +1866,8 @@ ffs_bufwrite(struct buf *bp) */ BO_LOCK(bp->b_bufobj); if (bp->b_vflags & BV_BKGRDINPROG) { + KASSERT(bp->b_fsprivate3 != NULL, + ("ffs_bufwrite: lost bg buffer")); if (bp->b_flags & B_ASYNC) { BO_UNLOCK(bp->b_bufobj); splx(s); @@ -1906,8 +1910,11 @@ ffs_bufwrite(struct buf *bp) newbp->b_lblkno = bp->b_lblkno; newbp->b_xflags |= BX_BKGRDMARKER; BO_LOCK(bp->b_bufobj); + KASSERT((bp->b_vflags & BV_BKGRDINPROG) == 0, + ("bufwrite: already started background dwrite")); bp->b_vflags |= BV_BKGRDINPROG; bgetvp(bp->b_vp, newbp); + bp->b_fsprivate3 = newbp; BO_UNLOCK(bp->b_bufobj); newbp->b_bufobj = &bp->b_vp->v_bufobj; newbp->b_blkno = bp->b_blkno;