- Add an interlock argument to BUF_LOCK and BUF_TIMELOCK.
- Remove the buftimelock mutex and acquire the buf's interlock to protect these fields instead. - Hold the vnode interlock while locking bufs on the clean/dirty queues. This reduces some cases from one BUF_LOCK with a LK_NOWAIT and another BUF_LOCK with a LK_TIMEFAIL to a single lock. Reviewed by: arch, mckusick
This commit is contained in:
parent
07159f9c56
commit
17661e5ac4
@ -814,7 +814,7 @@ build_rq_buffer(struct rqelement *rqe, struct plex *plex)
|
|||||||
panic("build_rq_buffer: rqe already locked"); /* XXX remove this when we're sure */
|
panic("build_rq_buffer: rqe already locked"); /* XXX remove this when we're sure */
|
||||||
#endif
|
#endif
|
||||||
BUF_LOCKINIT(bp); /* get a lock for the buffer */
|
BUF_LOCKINIT(bp); /* get a lock for the buffer */
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE); /* and lock it */
|
BUF_LOCK(bp, LK_EXCLUSIVE, NULL); /* and lock it */
|
||||||
BUF_KERNPROC(bp);
|
BUF_KERNPROC(bp);
|
||||||
rqe->flags |= XFR_BUFLOCKED;
|
rqe->flags |= XFR_BUFLOCKED;
|
||||||
bp->b_iodone = complete_rqe;
|
bp->b_iodone = complete_rqe;
|
||||||
@ -949,7 +949,7 @@ sdio(struct buf *bp)
|
|||||||
sbp->b.b_blkno = bp->b_blkno + sd->driveoffset;
|
sbp->b.b_blkno = bp->b_blkno + sd->driveoffset;
|
||||||
sbp->b.b_iodone = sdio_done; /* come here on completion */
|
sbp->b.b_iodone = sdio_done; /* come here on completion */
|
||||||
BUF_LOCKINIT(&sbp->b); /* get a lock for the buffer */
|
BUF_LOCKINIT(&sbp->b); /* get a lock for the buffer */
|
||||||
BUF_LOCK(&sbp->b, LK_EXCLUSIVE); /* and lock it */
|
BUF_LOCK(&sbp->b, LK_EXCLUSIVE, NULL); /* and lock it */
|
||||||
BUF_KERNPROC(&sbp->b);
|
BUF_KERNPROC(&sbp->b);
|
||||||
sbp->bp = bp; /* note the address of the original header */
|
sbp->bp = bp; /* note the address of the original header */
|
||||||
sbp->sdno = sd->sdno; /* note for statistics */
|
sbp->sdno = sd->sdno; /* note for statistics */
|
||||||
|
@ -170,7 +170,7 @@ extern u_char *fragtbl[];
|
|||||||
s = splbio(); \
|
s = splbio(); \
|
||||||
flags = (bp)->b_flags; \
|
flags = (bp)->b_flags; \
|
||||||
(bp)->b_flags &= ~(B_DIRTY | B_LOCKED); \
|
(bp)->b_flags &= ~(B_DIRTY | B_LOCKED); \
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE); \
|
BUF_LOCK(bp, LK_EXCLUSIVE, NULL); \
|
||||||
bremfree(bp); \
|
bremfree(bp); \
|
||||||
splx(s); \
|
splx(s); \
|
||||||
if (flags & B_DIRTY) \
|
if (flags & B_DIRTY) \
|
||||||
|
@ -170,7 +170,7 @@ extern u_char *fragtbl[];
|
|||||||
s = splbio(); \
|
s = splbio(); \
|
||||||
flags = (bp)->b_flags; \
|
flags = (bp)->b_flags; \
|
||||||
(bp)->b_flags &= ~(B_DIRTY | B_LOCKED); \
|
(bp)->b_flags &= ~(B_DIRTY | B_LOCKED); \
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE); \
|
BUF_LOCK(bp, LK_EXCLUSIVE, NULL); \
|
||||||
bremfree(bp); \
|
bremfree(bp); \
|
||||||
splx(s); \
|
splx(s); \
|
||||||
if (flags & B_DIRTY) \
|
if (flags & B_DIRTY) \
|
||||||
|
@ -232,19 +232,16 @@ debuglockmgr(lkp, flags, interlkp, td, name, file, line)
|
|||||||
else
|
else
|
||||||
thr = td;
|
thr = td;
|
||||||
|
|
||||||
if ((flags & (LK_NOWAIT|LK_RELEASE)) == 0) {
|
if ((flags & LK_INTERNAL) == 0)
|
||||||
if ((flags & LK_INTERLOCK) == 0)
|
mtx_lock(lkp->lk_interlock);
|
||||||
WITNESS_SLEEP(1, NULL);
|
|
||||||
else
|
|
||||||
WITNESS_SLEEP(1, &interlkp->mtx_object);
|
|
||||||
}
|
|
||||||
|
|
||||||
mtx_lock(lkp->lk_interlock);
|
|
||||||
if (flags & LK_INTERLOCK) {
|
if (flags & LK_INTERLOCK) {
|
||||||
mtx_assert(interlkp, MA_OWNED | MA_NOTRECURSED);
|
mtx_assert(interlkp, MA_OWNED | MA_NOTRECURSED);
|
||||||
mtx_unlock(interlkp);
|
mtx_unlock(interlkp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & (LK_NOWAIT|LK_RELEASE)) == 0)
|
||||||
|
WITNESS_SLEEP(1, &lkp->lk_interlock->mtx_object);
|
||||||
|
|
||||||
if (panicstr != NULL) {
|
if (panicstr != NULL) {
|
||||||
mtx_unlock(lkp->lk_interlock);
|
mtx_unlock(lkp->lk_interlock);
|
||||||
return (0);
|
return (0);
|
||||||
|
@ -68,7 +68,6 @@ struct buf_ops buf_ops_bio = {
|
|||||||
* carnal knowledge of buffers. This knowledge should be moved to vfs_bio.c.
|
* carnal knowledge of buffers. This knowledge should be moved to vfs_bio.c.
|
||||||
*/
|
*/
|
||||||
struct buf *buf; /* buffer header pool */
|
struct buf *buf; /* buffer header pool */
|
||||||
struct mtx buftimelock; /* Interlock on setting prio and timo */
|
|
||||||
|
|
||||||
static void vm_hold_free_pages(struct buf * bp, vm_offset_t from,
|
static void vm_hold_free_pages(struct buf * bp, vm_offset_t from,
|
||||||
vm_offset_t to);
|
vm_offset_t to);
|
||||||
@ -519,7 +518,6 @@ bufinit(void)
|
|||||||
#ifdef USE_BUFHASH
|
#ifdef USE_BUFHASH
|
||||||
LIST_INIT(&invalhash);
|
LIST_INIT(&invalhash);
|
||||||
#endif
|
#endif
|
||||||
mtx_init(&buftimelock, "buftime lock", NULL, MTX_DEF);
|
|
||||||
mtx_init(&bqlock, "buf queue lock", NULL, MTX_DEF);
|
mtx_init(&bqlock, "buf queue lock", NULL, MTX_DEF);
|
||||||
mtx_init(&rbreqlock, "runningbufspace lock", NULL, MTX_DEF);
|
mtx_init(&rbreqlock, "runningbufspace lock", NULL, MTX_DEF);
|
||||||
mtx_init(&nblock, "needsbuffer lock", NULL, MTX_DEF);
|
mtx_init(&nblock, "needsbuffer lock", NULL, MTX_DEF);
|
||||||
@ -967,7 +965,7 @@ vfs_backgroundwritedone(bp)
|
|||||||
* queue if it currently resides there.
|
* queue if it currently resides there.
|
||||||
*/
|
*/
|
||||||
origbp->b_flags &= ~B_LOCKED;
|
origbp->b_flags &= ~B_LOCKED;
|
||||||
if (BUF_LOCK(origbp, LK_EXCLUSIVE | LK_NOWAIT) == 0) {
|
if (BUF_LOCK(origbp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0) {
|
||||||
bremfree(origbp);
|
bremfree(origbp);
|
||||||
bqrelse(origbp);
|
bqrelse(origbp);
|
||||||
}
|
}
|
||||||
@ -1630,7 +1628,7 @@ vfs_bio_clcheck(struct vnode *vp, int size, daddr_t lblkno, daddr_t blkno)
|
|||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* If the buf is busy we don't want to wait for it */
|
/* If the buf is busy we don't want to wait for it */
|
||||||
if (BUF_LOCK(bpa, LK_EXCLUSIVE | LK_NOWAIT) != 0)
|
if (BUF_LOCK(bpa, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0)
|
||||||
return (0);
|
return (0);
|
||||||
|
|
||||||
/* Only cluster with valid clusterable delayed write buffers */
|
/* Only cluster with valid clusterable delayed write buffers */
|
||||||
@ -1710,7 +1708,7 @@ vfs_bio_awrite(struct buf * bp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE);
|
BUF_LOCK(bp, LK_EXCLUSIVE, NULL);
|
||||||
bremfree(bp);
|
bremfree(bp);
|
||||||
bp->b_flags |= B_ASYNC;
|
bp->b_flags |= B_ASYNC;
|
||||||
|
|
||||||
@ -1870,7 +1868,7 @@ restart:
|
|||||||
* remains valid only for QUEUE_EMPTY[KVA] bp's.
|
* remains valid only for QUEUE_EMPTY[KVA] bp's.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT) != 0)
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0)
|
||||||
panic("getnewbuf: locked buf");
|
panic("getnewbuf: locked buf");
|
||||||
bremfreel(bp);
|
bremfreel(bp);
|
||||||
mtx_unlock(&bqlock);
|
mtx_unlock(&bqlock);
|
||||||
@ -2147,7 +2145,7 @@ flushbufqueues(void)
|
|||||||
if ((bp->b_xflags & BX_BKGRDINPROG) != 0)
|
if ((bp->b_xflags & BX_BKGRDINPROG) != 0)
|
||||||
continue;
|
continue;
|
||||||
if (bp->b_flags & B_INVAL) {
|
if (bp->b_flags & B_INVAL) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT) != 0)
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0)
|
||||||
panic("flushbufqueues: locked buf");
|
panic("flushbufqueues: locked buf");
|
||||||
bremfreel(bp);
|
bremfreel(bp);
|
||||||
mtx_unlock(&bqlock);
|
mtx_unlock(&bqlock);
|
||||||
@ -2182,7 +2180,7 @@ flushbufqueues(void)
|
|||||||
if ((bp->b_xflags & BX_BKGRDINPROG) != 0)
|
if ((bp->b_xflags & BX_BKGRDINPROG) != 0)
|
||||||
continue;
|
continue;
|
||||||
if (bp->b_flags & B_INVAL) {
|
if (bp->b_flags & B_INVAL) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT) != 0)
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) != 0)
|
||||||
panic("flushbufqueues: locked buf");
|
panic("flushbufqueues: locked buf");
|
||||||
bremfreel(bp);
|
bremfreel(bp);
|
||||||
mtx_unlock(&bqlock);
|
mtx_unlock(&bqlock);
|
||||||
@ -2407,6 +2405,7 @@ getblk(struct vnode * vp, daddr_t blkno, int size, int slpflag, int slptimeo)
|
|||||||
{
|
{
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
int s;
|
int s;
|
||||||
|
int error;
|
||||||
#ifdef USE_BUFHASH
|
#ifdef USE_BUFHASH
|
||||||
struct bufhashhdr *bh;
|
struct bufhashhdr *bh;
|
||||||
#endif
|
#endif
|
||||||
@ -2437,19 +2436,24 @@ loop:
|
|||||||
|
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
if ((bp = gbincore(vp, blkno))) {
|
if ((bp = gbincore(vp, blkno))) {
|
||||||
VI_UNLOCK(vp);
|
|
||||||
/*
|
/*
|
||||||
* Buffer is in-core. If the buffer is not busy, it must
|
* Buffer is in-core. If the buffer is not busy, it must
|
||||||
* be on a queue.
|
* be on a queue.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
error = BUF_TIMELOCK(bp,
|
||||||
if (BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL,
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
|
||||||
"getblk", slpflag, slptimeo) == ENOLCK)
|
VI_MTX(vp), "getblk", slpflag, slptimeo);
|
||||||
goto loop;
|
|
||||||
splx(s);
|
/*
|
||||||
return (struct buf *) NULL;
|
* If we slept and got the lock we have to restart in case
|
||||||
}
|
* the buffer changed identities.
|
||||||
|
*/
|
||||||
|
if (error == ENOLCK)
|
||||||
|
goto loop;
|
||||||
|
/* We timed out or were interrupted. */
|
||||||
|
else if (error)
|
||||||
|
return (NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The buffer is locked. B_CACHE is cleared if the buffer is
|
* The buffer is locked. B_CACHE is cleared if the buffer is
|
||||||
|
@ -403,7 +403,8 @@ cluster_rbuild(vp, filesize, lbn, blkno, size, run, fbp)
|
|||||||
*/
|
*/
|
||||||
if ((tbp = incore(vp, lbn + i)) != NULL &&
|
if ((tbp = incore(vp, lbn + i)) != NULL &&
|
||||||
(tbp->b_flags & B_INVAL) == 0) {
|
(tbp->b_flags & B_INVAL) == 0) {
|
||||||
if (BUF_LOCK(tbp, LK_EXCLUSIVE | LK_NOWAIT))
|
if (BUF_LOCK(tbp,
|
||||||
|
LK_EXCLUSIVE | LK_NOWAIT, NULL))
|
||||||
break;
|
break;
|
||||||
BUF_UNLOCK(tbp);
|
BUF_UNLOCK(tbp);
|
||||||
|
|
||||||
@ -794,7 +795,7 @@ cluster_wbuild(vp, size, start_lbn, len)
|
|||||||
*/
|
*/
|
||||||
if (((tbp = incore(vp, start_lbn)) == NULL) ||
|
if (((tbp = incore(vp, start_lbn)) == NULL) ||
|
||||||
((tbp->b_flags & (B_LOCKED | B_INVAL | B_DELWRI)) != B_DELWRI) ||
|
((tbp->b_flags & (B_LOCKED | B_INVAL | B_DELWRI)) != B_DELWRI) ||
|
||||||
BUF_LOCK(tbp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
BUF_LOCK(tbp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
|
||||||
++start_lbn;
|
++start_lbn;
|
||||||
--len;
|
--len;
|
||||||
splx(s);
|
splx(s);
|
||||||
@ -884,7 +885,8 @@ cluster_wbuild(vp, size, start_lbn, len)
|
|||||||
(bp->b_flags & (B_VMIO | B_NEEDCOMMIT))) ||
|
(bp->b_flags & (B_VMIO | B_NEEDCOMMIT))) ||
|
||||||
(tbp->b_flags & B_LOCKED) ||
|
(tbp->b_flags & B_LOCKED) ||
|
||||||
tbp->b_wcred != bp->b_wcred ||
|
tbp->b_wcred != bp->b_wcred ||
|
||||||
BUF_LOCK(tbp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
BUF_LOCK(tbp, LK_EXCLUSIVE | LK_NOWAIT,
|
||||||
|
NULL)) {
|
||||||
splx(s);
|
splx(s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -745,7 +745,7 @@ loop2:
|
|||||||
if ((bp->b_vflags & BV_SCANNED) != 0)
|
if ((bp->b_vflags & BV_SCANNED) != 0)
|
||||||
continue;
|
continue;
|
||||||
bp->b_vflags |= BV_SCANNED;
|
bp->b_vflags |= BV_SCANNED;
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
|
||||||
continue;
|
continue;
|
||||||
VI_UNLOCK(vp);
|
VI_UNLOCK(vp);
|
||||||
if ((bp->b_flags & B_DELWRI) == 0)
|
if ((bp->b_flags & B_DELWRI) == 0)
|
||||||
|
@ -1218,17 +1218,15 @@ flushbuflist(blist, flags, vp, slpflag, slptimeo, errorp)
|
|||||||
|
|
||||||
for (found = 0, bp = blist; bp; bp = nbp) {
|
for (found = 0, bp = blist; bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
|
||||||
if (((flags & V_NORMAL) && (bp->b_xflags & BX_ALTDATA)) ||
|
if (((flags & V_NORMAL) && (bp->b_xflags & BX_ALTDATA)) ||
|
||||||
((flags & V_ALT) && (bp->b_xflags & BX_ALTDATA) == 0)) {
|
((flags & V_ALT) && (bp->b_xflags & BX_ALTDATA) == 0)) {
|
||||||
VI_LOCK(vp);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found += 1;
|
found += 1;
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
error = BUF_TIMELOCK(bp,
|
||||||
error = BUF_TIMELOCK(bp,
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK, VI_MTX(vp),
|
||||||
LK_EXCLUSIVE | LK_SLEEPFAIL,
|
"flushbuf", slpflag, slptimeo);
|
||||||
"flushbuf", slpflag, slptimeo);
|
if (error) {
|
||||||
if (error != ENOLCK)
|
if (error != ENOLCK)
|
||||||
*errorp = error;
|
*errorp = error;
|
||||||
goto done;
|
goto done;
|
||||||
@ -1303,50 +1301,48 @@ restart:
|
|||||||
anyfreed = 0;
|
anyfreed = 0;
|
||||||
for (bp = TAILQ_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_cleanblkhd); bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
|
||||||
if (bp->b_lblkno >= trunclbn) {
|
if (bp->b_lblkno >= trunclbn) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (BUF_LOCK(bp,
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL);
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp)) == ENOLCK)
|
||||||
goto restart;
|
goto restart;
|
||||||
} else {
|
|
||||||
bremfree(bp);
|
bremfree(bp);
|
||||||
bp->b_flags |= (B_INVAL | B_RELBUF);
|
bp->b_flags |= (B_INVAL | B_RELBUF);
|
||||||
bp->b_flags &= ~B_ASYNC;
|
bp->b_flags &= ~B_ASYNC;
|
||||||
brelse(bp);
|
brelse(bp);
|
||||||
anyfreed = 1;
|
anyfreed = 1;
|
||||||
}
|
|
||||||
if (nbp &&
|
if (nbp &&
|
||||||
(((nbp->b_xflags & BX_VNCLEAN) == 0) ||
|
(((nbp->b_xflags & BX_VNCLEAN) == 0) ||
|
||||||
(nbp->b_vp != vp) ||
|
(nbp->b_vp != vp) ||
|
||||||
(nbp->b_flags & B_DELWRI))) {
|
(nbp->b_flags & B_DELWRI))) {
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
VI_LOCK(vp);
|
||||||
}
|
}
|
||||||
VI_LOCK(vp);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
|
||||||
if (bp->b_lblkno >= trunclbn) {
|
if (bp->b_lblkno >= trunclbn) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (BUF_LOCK(bp,
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL);
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp)) == ENOLCK)
|
||||||
goto restart;
|
goto restart;
|
||||||
} else {
|
bremfree(bp);
|
||||||
bremfree(bp);
|
bp->b_flags |= (B_INVAL | B_RELBUF);
|
||||||
bp->b_flags |= (B_INVAL | B_RELBUF);
|
bp->b_flags &= ~B_ASYNC;
|
||||||
bp->b_flags &= ~B_ASYNC;
|
brelse(bp);
|
||||||
brelse(bp);
|
anyfreed = 1;
|
||||||
anyfreed = 1;
|
|
||||||
}
|
|
||||||
if (nbp &&
|
if (nbp &&
|
||||||
(((nbp->b_xflags & BX_VNDIRTY) == 0) ||
|
(((nbp->b_xflags & BX_VNDIRTY) == 0) ||
|
||||||
(nbp->b_vp != vp) ||
|
(nbp->b_vp != vp) ||
|
||||||
(nbp->b_flags & B_DELWRI) == 0)) {
|
(nbp->b_flags & B_DELWRI) == 0)) {
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
VI_LOCK(vp);
|
||||||
}
|
}
|
||||||
VI_LOCK(vp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1354,24 +1350,21 @@ restart:
|
|||||||
restartsync:
|
restartsync:
|
||||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
|
||||||
if ((bp->b_flags & B_DELWRI) && (bp->b_lblkno < 0)) {
|
if ((bp->b_flags & B_DELWRI) && (bp->b_lblkno < 0)) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (BUF_LOCK(bp,
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE|LK_SLEEPFAIL);
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp)) == ENOLCK)
|
||||||
goto restart;
|
goto restart;
|
||||||
} else {
|
bremfree(bp);
|
||||||
bremfree(bp);
|
if (bp->b_vp == vp)
|
||||||
if (bp->b_vp == vp) {
|
bp->b_flags |= B_ASYNC;
|
||||||
bp->b_flags |= B_ASYNC;
|
else
|
||||||
} else {
|
bp->b_flags &= ~B_ASYNC;
|
||||||
bp->b_flags &= ~B_ASYNC;
|
|
||||||
}
|
BUF_WRITE(bp);
|
||||||
BUF_WRITE(bp);
|
|
||||||
}
|
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
goto restartsync;
|
goto restartsync;
|
||||||
}
|
}
|
||||||
VI_LOCK(vp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2658,10 +2658,11 @@ again:
|
|||||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||||
if (bvecpos >= bvecsize)
|
if (bvecpos >= bvecsize)
|
||||||
break;
|
break;
|
||||||
VI_UNLOCK(vp);
|
|
||||||
if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) !=
|
if ((bp->b_flags & (B_DELWRI | B_NEEDCOMMIT)) !=
|
||||||
(B_DELWRI | B_NEEDCOMMIT) ||
|
(B_DELWRI | B_NEEDCOMMIT) ||
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
BUF_LOCK(bp,
|
||||||
|
LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp))) {
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
continue;
|
continue;
|
||||||
@ -2785,14 +2786,13 @@ loop:
|
|||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (waitfor != MNT_WAIT || passone)
|
||||||
if (waitfor != MNT_WAIT || passone) {
|
|
||||||
VI_LOCK(vp);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL,
|
error = BUF_TIMELOCK(bp,
|
||||||
"nfsfsync", slpflag, slptimeo);
|
LK_EXCLUSIVE | LK_SLEEPFAIL | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp), "nfsfsync", slpflag, slptimeo);
|
||||||
splx(s);
|
splx(s);
|
||||||
if (error == 0)
|
if (error == 0)
|
||||||
panic("nfs_fsync: inconsistent lock");
|
panic("nfs_fsync: inconsistent lock");
|
||||||
|
@ -3687,6 +3687,7 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
|
|||||||
}
|
}
|
||||||
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
|
VI_LOCK(vp);
|
||||||
while (cnt > 0) {
|
while (cnt > 0) {
|
||||||
struct buf *bp;
|
struct buf *bp;
|
||||||
|
|
||||||
@ -3700,16 +3701,18 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
|
|||||||
* should not be set if B_INVAL is set there could be
|
* should not be set if B_INVAL is set there could be
|
||||||
* a race here since we haven't locked the buffer).
|
* a race here since we haven't locked the buffer).
|
||||||
*/
|
*/
|
||||||
if ((bp = incore(vp, lblkno)) != NULL &&
|
if ((bp = gbincore(vp, lblkno)) != NULL &&
|
||||||
(bp->b_flags & (B_DELWRI|B_INVAL)) == B_DELWRI) {
|
(bp->b_flags & (B_DELWRI|B_INVAL)) == B_DELWRI) {
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL);
|
LK_INTERLOCK, VI_MTX(vp)) == ENOLCK) {
|
||||||
|
VI_LOCK(vp);
|
||||||
continue; /* retry */
|
continue; /* retry */
|
||||||
}
|
}
|
||||||
bremfree(bp);
|
bremfree(bp);
|
||||||
bp->b_flags &= ~B_ASYNC;
|
bp->b_flags &= ~B_ASYNC;
|
||||||
BUF_WRITE(bp);
|
BUF_WRITE(bp);
|
||||||
++nfs_commit_miss;
|
++nfs_commit_miss;
|
||||||
|
VI_LOCK(vp);
|
||||||
}
|
}
|
||||||
++nfs_commit_blks;
|
++nfs_commit_blks;
|
||||||
if (cnt < iosize)
|
if (cnt < iosize)
|
||||||
@ -3717,6 +3720,7 @@ nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
|
|||||||
cnt -= iosize;
|
cnt -= iosize;
|
||||||
++lblkno;
|
++lblkno;
|
||||||
}
|
}
|
||||||
|
VI_UNLOCK(vp);
|
||||||
splx(s);
|
splx(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -273,7 +273,6 @@ struct buf {
|
|||||||
/*
|
/*
|
||||||
* Buffer locking
|
* Buffer locking
|
||||||
*/
|
*/
|
||||||
extern struct mtx buftimelock; /* Interlock on setting prio and timo */
|
|
||||||
extern const char *buf_wmesg; /* Default buffer lock message */
|
extern const char *buf_wmesg; /* Default buffer lock message */
|
||||||
#define BUF_WMESG "bufwait"
|
#define BUF_WMESG "bufwait"
|
||||||
#include <sys/proc.h> /* XXX for curthread */
|
#include <sys/proc.h> /* XXX for curthread */
|
||||||
@ -288,37 +287,39 @@ extern const char *buf_wmesg; /* Default buffer lock message */
|
|||||||
*
|
*
|
||||||
* Get a lock sleeping non-interruptably until it becomes available.
|
* Get a lock sleeping non-interruptably until it becomes available.
|
||||||
*/
|
*/
|
||||||
static __inline int BUF_LOCK(struct buf *, int);
|
static __inline int BUF_LOCK(struct buf *, int, struct mtx *);
|
||||||
static __inline int
|
static __inline int
|
||||||
BUF_LOCK(struct buf *bp, int locktype)
|
BUF_LOCK(struct buf *bp, int locktype, struct mtx *interlock)
|
||||||
{
|
{
|
||||||
int s, ret;
|
int s, ret;
|
||||||
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
mtx_lock(&buftimelock);
|
mtx_lock(bp->b_lock.lk_interlock);
|
||||||
locktype |= LK_INTERLOCK;
|
locktype |= LK_INTERNAL;
|
||||||
bp->b_lock.lk_wmesg = buf_wmesg;
|
bp->b_lock.lk_wmesg = buf_wmesg;
|
||||||
bp->b_lock.lk_prio = PRIBIO + 4;
|
bp->b_lock.lk_prio = PRIBIO + 4;
|
||||||
ret = lockmgr(&(bp)->b_lock, locktype, &buftimelock, curthread);
|
ret = lockmgr(&(bp)->b_lock, locktype, interlock, curthread);
|
||||||
splx(s);
|
splx(s);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Get a lock sleeping with specified interruptably and timeout.
|
* Get a lock sleeping with specified interruptably and timeout.
|
||||||
*/
|
*/
|
||||||
static __inline int BUF_TIMELOCK(struct buf *, int, char *, int, int);
|
static __inline int BUF_TIMELOCK(struct buf *, int, struct mtx *,
|
||||||
|
char *, int, int);
|
||||||
static __inline int
|
static __inline int
|
||||||
BUF_TIMELOCK(struct buf *bp, int locktype, char *wmesg, int catch, int timo)
|
BUF_TIMELOCK(struct buf *bp, int locktype, struct mtx *interlock,
|
||||||
|
char *wmesg, int catch, int timo)
|
||||||
{
|
{
|
||||||
int s, ret;
|
int s, ret;
|
||||||
|
|
||||||
s = splbio();
|
s = splbio();
|
||||||
mtx_lock(&buftimelock);
|
mtx_lock(bp->b_lock.lk_interlock);
|
||||||
locktype |= LK_INTERLOCK | LK_TIMELOCK;
|
locktype |= LK_INTERNAL | LK_TIMELOCK;
|
||||||
bp->b_lock.lk_wmesg = wmesg;
|
bp->b_lock.lk_wmesg = wmesg;
|
||||||
bp->b_lock.lk_prio = (PRIBIO + 4) | catch;
|
bp->b_lock.lk_prio = (PRIBIO + 4) | catch;
|
||||||
bp->b_lock.lk_timo = timo;
|
bp->b_lock.lk_timo = timo;
|
||||||
ret = lockmgr(&(bp)->b_lock, (locktype), &buftimelock, curthread);
|
ret = lockmgr(&(bp)->b_lock, (locktype), interlock, curthread);
|
||||||
splx(s);
|
splx(s);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -149,6 +149,7 @@ struct lock {
|
|||||||
*/
|
*/
|
||||||
#define LK_RETRY 0x00020000 /* vn_lock: retry until locked */
|
#define LK_RETRY 0x00020000 /* vn_lock: retry until locked */
|
||||||
#define LK_THISLAYER 0x00040000 /* vn_lock: lock/unlock only current layer */
|
#define LK_THISLAYER 0x00040000 /* vn_lock: lock/unlock only current layer */
|
||||||
|
#define LK_INTERNAL 0x00080000/* The internal lock is already held */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Internal state flags corresponding to lk_sharecount, and lk_waitcount
|
* Internal state flags corresponding to lk_sharecount, and lk_waitcount
|
||||||
|
@ -327,7 +327,7 @@ interlocked_sleep(lk, op, ident, mtx, flags, wmesg, timo)
|
|||||||
retval = msleep(ident, mtx, flags, wmesg, timo);
|
retval = msleep(ident, mtx, flags, wmesg, timo);
|
||||||
break;
|
break;
|
||||||
case LOCKBUF:
|
case LOCKBUF:
|
||||||
retval = BUF_LOCK((struct buf *)ident, flags);
|
retval = BUF_LOCK((struct buf *)ident, flags, NULL);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
panic("interlocked_sleep: unknown operation");
|
panic("interlocked_sleep: unknown operation");
|
||||||
@ -4890,11 +4890,11 @@ softdep_fsync_mountdev(vp)
|
|||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
for (bp = TAILQ_FIRST(&vp->v_dirtyblkhd); bp; bp = nbp) {
|
||||||
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
nbp = TAILQ_NEXT(bp, b_vnbufs);
|
||||||
VI_UNLOCK(vp);
|
|
||||||
/*
|
/*
|
||||||
* If it is already scheduled, skip to the next buffer.
|
* If it is already scheduled, skip to the next buffer.
|
||||||
*/
|
*/
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT)) {
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK,
|
||||||
|
VI_MTX(vp))) {
|
||||||
VI_LOCK(vp);
|
VI_LOCK(vp);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -5807,7 +5807,8 @@ getdirtybuf(bpp, waitfor)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
if ((bp = *bpp) == NULL)
|
if ((bp = *bpp) == NULL)
|
||||||
return (0);
|
return (0);
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT) == 0) {
|
/* XXX Probably needs interlock */
|
||||||
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL) == 0) {
|
||||||
if ((bp->b_xflags & BX_BKGRDINPROG) == 0)
|
if ((bp->b_xflags & BX_BKGRDINPROG) == 0)
|
||||||
break;
|
break;
|
||||||
BUF_UNLOCK(bp);
|
BUF_UNLOCK(bp);
|
||||||
|
@ -200,7 +200,7 @@ loop:
|
|||||||
bp->b_vflags |= BV_SCANNED;
|
bp->b_vflags |= BV_SCANNED;
|
||||||
if ((skipmeta == 1 && bp->b_lblkno < 0))
|
if ((skipmeta == 1 && bp->b_lblkno < 0))
|
||||||
continue;
|
continue;
|
||||||
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT))
|
if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL))
|
||||||
continue;
|
continue;
|
||||||
if (!wait && LIST_FIRST(&bp->b_dep) != NULL &&
|
if (!wait && LIST_FIRST(&bp->b_dep) != NULL &&
|
||||||
(bp->b_flags & B_DEFERRED) == 0 &&
|
(bp->b_flags & B_DEFERRED) == 0 &&
|
||||||
|
@ -345,7 +345,7 @@ initpbuf(struct buf *bp)
|
|||||||
bp->b_error = 0;
|
bp->b_error = 0;
|
||||||
bp->b_magic = B_MAGIC_BIO;
|
bp->b_magic = B_MAGIC_BIO;
|
||||||
bp->b_op = &buf_ops_bio;
|
bp->b_op = &buf_ops_bio;
|
||||||
BUF_LOCK(bp, LK_EXCLUSIVE);
|
BUF_LOCK(bp, LK_EXCLUSIVE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
x
Reference in New Issue
Block a user