Prepare to replace the buf splay with a trie:
- Don't insert BKGRDMARKER bufs into the splay or dirty/clean buf lists. No consumers need to find them there and it complicates the tree. These flags are all FFS specific and could be moved out of the buf cache. - Use pbgetvp() and pbrelvp() to associate the background and journal bufs with the vp. Not only is this much cheaper it makes more sense for these transient bufs. - Fix the assertions in pbget* and pbrel*. It's not safe to check list pointers which were never initialized. Use the BX flags instead. We also check B_PAGING in reassignbuf() so this should cover all cases. Discussed with: kib, mckusick, attilio Sponsored by: EMC / Isilon Storage Division
This commit is contained in:
parent
e36a4a7ea0
commit
26089666b6
@ -794,8 +794,6 @@ ext2_clusteralloc(struct inode *ip, int cg, daddr_t bpref, int len)
|
||||
goto fail_lock;
|
||||
|
||||
bbp = (char *)bp->b_data;
|
||||
bp->b_xflags |= BX_BKGRDWRITE;
|
||||
|
||||
EXT2_LOCK(ump);
|
||||
/*
|
||||
* Check to see if a cluster of the needed size (or bigger) is
|
||||
|
@ -1312,8 +1312,7 @@ flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag,
|
||||
xflags = 0;
|
||||
if (nbp != NULL) {
|
||||
lblkno = nbp->b_lblkno;
|
||||
xflags = nbp->b_xflags &
|
||||
(BX_BKGRDMARKER | BX_VNDIRTY | BX_VNCLEAN);
|
||||
xflags = nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN);
|
||||
}
|
||||
retval = EAGAIN;
|
||||
error = BUF_TIMELOCK(bp,
|
||||
@ -1357,8 +1356,7 @@ flushbuflist(struct bufv *bufv, int flags, struct bufobj *bo, int slpflag,
|
||||
if (nbp != NULL &&
|
||||
(nbp->b_bufobj != bo ||
|
||||
nbp->b_lblkno != lblkno ||
|
||||
(nbp->b_xflags &
|
||||
(BX_BKGRDMARKER | BX_VNDIRTY | BX_VNCLEAN)) != xflags))
|
||||
(nbp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) != xflags))
|
||||
break; /* nbp invalid */
|
||||
}
|
||||
return (retval);
|
||||
@ -1501,9 +1499,7 @@ buf_splay(daddr_t lblkno, b_xflags_t xflags, struct buf *root)
|
||||
return (NULL);
|
||||
lefttreemax = righttreemin = &dummy;
|
||||
for (;;) {
|
||||
if (lblkno < root->b_lblkno ||
|
||||
(lblkno == root->b_lblkno &&
|
||||
(xflags & BX_BKGRDMARKER) < (root->b_xflags & BX_BKGRDMARKER))) {
|
||||
if (lblkno < root->b_lblkno) {
|
||||
if ((y = root->b_left) == NULL)
|
||||
break;
|
||||
if (lblkno < y->b_lblkno) {
|
||||
@ -1517,9 +1513,7 @@ buf_splay(daddr_t lblkno, b_xflags_t xflags, struct buf *root)
|
||||
/* Link into the new root's right tree. */
|
||||
righttreemin->b_left = root;
|
||||
righttreemin = root;
|
||||
} else if (lblkno > root->b_lblkno ||
|
||||
(lblkno == root->b_lblkno &&
|
||||
(xflags & BX_BKGRDMARKER) > (root->b_xflags & BX_BKGRDMARKER))) {
|
||||
} else if (lblkno > root->b_lblkno) {
|
||||
if ((y = root->b_right) == NULL)
|
||||
break;
|
||||
if (lblkno > y->b_lblkno) {
|
||||
@ -1603,9 +1597,7 @@ buf_vlist_add(struct buf *bp, struct bufobj *bo, b_xflags_t xflags)
|
||||
bp->b_left = NULL;
|
||||
bp->b_right = NULL;
|
||||
TAILQ_INSERT_TAIL(&bv->bv_hd, bp, b_bobufs);
|
||||
} else if (bp->b_lblkno < root->b_lblkno ||
|
||||
(bp->b_lblkno == root->b_lblkno &&
|
||||
(bp->b_xflags & BX_BKGRDMARKER) < (root->b_xflags & BX_BKGRDMARKER))) {
|
||||
} else if (bp->b_lblkno < root->b_lblkno) {
|
||||
bp->b_left = root->b_left;
|
||||
bp->b_right = root;
|
||||
root->b_left = NULL;
|
||||
@ -1638,20 +1630,18 @@ gbincore(struct bufobj *bo, daddr_t lblkno)
|
||||
struct buf *bp;
|
||||
|
||||
ASSERT_BO_LOCKED(bo);
|
||||
if ((bp = bo->bo_clean.bv_root) != NULL &&
|
||||
bp->b_lblkno == lblkno && !(bp->b_xflags & BX_BKGRDMARKER))
|
||||
if ((bp = bo->bo_clean.bv_root) != NULL && bp->b_lblkno == lblkno)
|
||||
return (bp);
|
||||
if ((bp = bo->bo_dirty.bv_root) != NULL &&
|
||||
bp->b_lblkno == lblkno && !(bp->b_xflags & BX_BKGRDMARKER))
|
||||
if ((bp = bo->bo_dirty.bv_root) != NULL && bp->b_lblkno == lblkno)
|
||||
return (bp);
|
||||
if ((bp = bo->bo_clean.bv_root) != NULL) {
|
||||
bo->bo_clean.bv_root = bp = buf_splay(lblkno, 0, bp);
|
||||
if (bp->b_lblkno == lblkno && !(bp->b_xflags & BX_BKGRDMARKER))
|
||||
if (bp->b_lblkno == lblkno)
|
||||
return (bp);
|
||||
}
|
||||
if ((bp = bo->bo_dirty.bv_root) != NULL) {
|
||||
bo->bo_dirty.bv_root = bp = buf_splay(lblkno, 0, bp);
|
||||
if (bp->b_lblkno == lblkno && !(bp->b_xflags & BX_BKGRDMARKER))
|
||||
if (bp->b_lblkno == lblkno)
|
||||
return (bp);
|
||||
}
|
||||
return (NULL);
|
||||
|
@ -3285,7 +3285,6 @@ softdep_process_journal(mp, needwk, flags)
|
||||
bp->b_lblkno = bp->b_blkno;
|
||||
bp->b_offset = bp->b_blkno * DEV_BSIZE;
|
||||
bp->b_bcount = size;
|
||||
bp->b_bufobj = &ump->um_devvp->v_bufobj;
|
||||
bp->b_flags &= ~B_INVAL;
|
||||
bp->b_flags |= B_VALIDSUSPWRT | B_NOCOPY;
|
||||
/*
|
||||
@ -3365,9 +3364,7 @@ softdep_process_journal(mp, needwk, flags)
|
||||
jblocks->jb_needseg = 0;
|
||||
WORKLIST_INSERT(&bp->b_dep, &jseg->js_list);
|
||||
FREE_LOCK(&lk);
|
||||
BO_LOCK(bp->b_bufobj);
|
||||
bgetvp(ump->um_devvp, bp);
|
||||
BO_UNLOCK(bp->b_bufobj);
|
||||
pbgetvp(ump->um_devvp, bp);
|
||||
/*
|
||||
* We only do the blocking wait once we find the journal
|
||||
* entry we're looking for.
|
||||
@ -3522,6 +3519,7 @@ handle_written_jseg(jseg, bp)
|
||||
* discarded.
|
||||
*/
|
||||
bp->b_flags |= B_INVAL | B_NOCACHE;
|
||||
pbrelvp(bp);
|
||||
complete_jsegs(jseg);
|
||||
}
|
||||
|
||||
@ -11450,6 +11448,7 @@ handle_written_bmsafemap(bmsafemap, bp)
|
||||
struct cg *cgp;
|
||||
struct fs *fs;
|
||||
ino_t ino;
|
||||
int foreground;
|
||||
int chgs;
|
||||
|
||||
if ((bmsafemap->sm_state & IOSTARTED) == 0)
|
||||
@ -11457,6 +11456,7 @@ handle_written_bmsafemap(bmsafemap, bp)
|
||||
ump = VFSTOUFS(bmsafemap->sm_list.wk_mp);
|
||||
chgs = 0;
|
||||
bmsafemap->sm_state &= ~IOSTARTED;
|
||||
foreground = (bp->b_xflags & BX_BKGRDMARKER) == 0;
|
||||
/*
|
||||
* Release journal work that was waiting on the write.
|
||||
*/
|
||||
@ -11477,7 +11477,8 @@ handle_written_bmsafemap(bmsafemap, bp)
|
||||
if (isset(inosused, ino))
|
||||
panic("handle_written_bmsafemap: "
|
||||
"re-allocated inode");
|
||||
if ((bp->b_xflags & BX_BKGRDMARKER) == 0) {
|
||||
/* Do the roll-forward only if it's a real copy. */
|
||||
if (foreground) {
|
||||
if ((jaddref->ja_mode & IFMT) == IFDIR)
|
||||
cgp->cg_cs.cs_ndir++;
|
||||
cgp->cg_cs.cs_nifree--;
|
||||
@ -11500,7 +11501,8 @@ handle_written_bmsafemap(bmsafemap, bp)
|
||||
jntmp) {
|
||||
if ((jnewblk->jn_state & UNDONE) == 0)
|
||||
continue;
|
||||
if ((bp->b_xflags & BX_BKGRDMARKER) == 0 &&
|
||||
/* Do the roll-forward only if it's a real copy. */
|
||||
if (foreground &&
|
||||
jnewblk_rollforward(jnewblk, fs, cgp, blksfree))
|
||||
chgs = 1;
|
||||
jnewblk->jn_state &= ~(UNDONE | NEWBLOCK);
|
||||
@ -11540,7 +11542,8 @@ handle_written_bmsafemap(bmsafemap, bp)
|
||||
return (0);
|
||||
}
|
||||
LIST_INSERT_HEAD(&ump->softdep_dirtycg, bmsafemap, sm_next);
|
||||
bdirty(bp);
|
||||
if (foreground)
|
||||
bdirty(bp);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
@ -2000,12 +2000,11 @@ ffs_backgroundwritedone(struct buf *bp)
|
||||
BO_LOCK(bufobj);
|
||||
if ((origbp = gbincore(bp->b_bufobj, bp->b_lblkno)) == NULL)
|
||||
panic("backgroundwritedone: lost buffer");
|
||||
/* Grab an extra reference to be dropped by the bufdone() below. */
|
||||
bufobj_wrefl(bufobj);
|
||||
BO_UNLOCK(bufobj);
|
||||
/*
|
||||
* Process dependencies then return any unfinished ones.
|
||||
*/
|
||||
pbrelvp(bp);
|
||||
if (!LIST_EMPTY(&bp->b_dep))
|
||||
buf_complete(bp);
|
||||
#ifdef SOFTUPDATES
|
||||
@ -2051,8 +2050,8 @@ ffs_backgroundwritedone(struct buf *bp)
|
||||
static int
|
||||
ffs_bufwrite(struct buf *bp)
|
||||
{
|
||||
int oldflags, s;
|
||||
struct buf *newbp;
|
||||
int oldflags;
|
||||
|
||||
CTR3(KTR_BUF, "bufwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags);
|
||||
if (bp->b_flags & B_INVAL) {
|
||||
@ -2064,7 +2063,6 @@ ffs_bufwrite(struct buf *bp)
|
||||
|
||||
if (!BUF_ISLOCKED(bp))
|
||||
panic("bufwrite: buffer is not busy???");
|
||||
s = splbio();
|
||||
/*
|
||||
* If a background write is already in progress, delay
|
||||
* writing this block if it is asynchronous. Otherwise
|
||||
@ -2074,7 +2072,6 @@ ffs_bufwrite(struct buf *bp)
|
||||
if (bp->b_vflags & BV_BKGRDINPROG) {
|
||||
if (bp->b_flags & B_ASYNC) {
|
||||
BO_UNLOCK(bp->b_bufobj);
|
||||
splx(s);
|
||||
bdwrite(bp);
|
||||
return (0);
|
||||
}
|
||||
@ -2105,25 +2102,19 @@ ffs_bufwrite(struct buf *bp)
|
||||
if (newbp == NULL)
|
||||
goto normal_write;
|
||||
|
||||
/*
|
||||
* set it to be identical to the old block. We have to
|
||||
* set b_lblkno and BKGRDMARKER before calling bgetvp()
|
||||
* to avoid confusing the splay tree and gbincore().
|
||||
*/
|
||||
KASSERT((bp->b_flags & B_UNMAPPED) == 0, ("Unmapped cg"));
|
||||
memcpy(newbp->b_data, bp->b_data, bp->b_bufsize);
|
||||
newbp->b_lblkno = bp->b_lblkno;
|
||||
newbp->b_xflags |= BX_BKGRDMARKER;
|
||||
BO_LOCK(bp->b_bufobj);
|
||||
bp->b_vflags |= BV_BKGRDINPROG;
|
||||
bgetvp(bp->b_vp, newbp);
|
||||
BO_UNLOCK(bp->b_bufobj);
|
||||
newbp->b_bufobj = &bp->b_vp->v_bufobj;
|
||||
newbp->b_xflags |= BX_BKGRDMARKER;
|
||||
newbp->b_lblkno = bp->b_lblkno;
|
||||
newbp->b_blkno = bp->b_blkno;
|
||||
newbp->b_offset = bp->b_offset;
|
||||
newbp->b_iodone = ffs_backgroundwritedone;
|
||||
newbp->b_flags |= B_ASYNC;
|
||||
newbp->b_flags &= ~B_INVAL;
|
||||
pbgetvp(bp->b_vp, newbp);
|
||||
|
||||
#ifdef SOFTUPDATES
|
||||
/*
|
||||
@ -2139,12 +2130,9 @@ ffs_bufwrite(struct buf *bp)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Initiate write on the copy, release the original to
|
||||
* the B_LOCKED queue so that it cannot go away until
|
||||
* the background write completes. If not locked it could go
|
||||
* away and then be reconstituted while it was being written.
|
||||
* If the reconstituted buffer were written, we could end up
|
||||
* with two background copies being written at the same time.
|
||||
* Initiate write on the copy, release the original. The
|
||||
* BKGRDINPROG flag prevents it from going away until
|
||||
* the background write completes.
|
||||
*/
|
||||
bqrelse(bp);
|
||||
bp = newbp;
|
||||
|
@ -469,17 +469,9 @@ pbrelvp(struct buf *bp)
|
||||
|
||||
KASSERT(bp->b_vp != NULL, ("pbrelvp: NULL"));
|
||||
KASSERT(bp->b_bufobj != NULL, ("pbrelvp: NULL bufobj"));
|
||||
KASSERT((bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) == 0,
|
||||
("pbrelvp: pager buf on vnode list."));
|
||||
|
||||
/* XXX REMOVE ME */
|
||||
BO_LOCK(bp->b_bufobj);
|
||||
if (TAILQ_NEXT(bp, b_bobufs) != NULL) {
|
||||
panic(
|
||||
"relpbuf(): b_vp was probably reassignbuf()d %p %x",
|
||||
bp,
|
||||
(int)bp->b_flags
|
||||
);
|
||||
}
|
||||
BO_UNLOCK(bp->b_bufobj);
|
||||
bp->b_vp = NULL;
|
||||
bp->b_bufobj = NULL;
|
||||
bp->b_flags &= ~B_PAGING;
|
||||
@ -494,17 +486,9 @@ pbrelbo(struct buf *bp)
|
||||
|
||||
KASSERT(bp->b_vp == NULL, ("pbrelbo: vnode"));
|
||||
KASSERT(bp->b_bufobj != NULL, ("pbrelbo: NULL bufobj"));
|
||||
KASSERT((bp->b_xflags & (BX_VNDIRTY | BX_VNCLEAN)) == 0,
|
||||
("pbrelbo: pager buf on vnode list."));
|
||||
|
||||
/* XXX REMOVE ME */
|
||||
BO_LOCK(bp->b_bufobj);
|
||||
if (TAILQ_NEXT(bp, b_bobufs) != NULL) {
|
||||
panic(
|
||||
"relpbuf(): b_vp was probably reassignbuf()d %p %x",
|
||||
bp,
|
||||
(int)bp->b_flags
|
||||
);
|
||||
}
|
||||
BO_UNLOCK(bp->b_bufobj);
|
||||
bp->b_bufobj = NULL;
|
||||
bp->b_flags &= ~B_PAGING;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user