- /*
- * If block was memory resident, let bread get it.
- * If block was not memory resident, the read was
- * started above, so just wait for the read to complete.
- */
- if (bp == NULL)
-#ifdef SECSIZE
- return (bread(dev, blkno, size, secsize));
-#else SECSIZE
- return (bread(vp, blkno, size, cred, bpp));
- return (biowait(bp));
-}
-
-/*
- * Synchronous write.
- * Release buffer on completion.
- */
-bwrite(bp)
- register struct buf *bp;
-{
- register int flag;
- int s, error;
-
- flag = bp->b_flags;
- bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
- if ((flag & B_DELWRI) == 0)
- u.u_ru.ru_oublock++; /* noone paid yet */
- else
- reassignbuf(bp, bp->b_vp);
- trace(TR_BWRITE, pack(bp->b_vp, bp->b_bcount), bp->b_lblkno);
- if (bp->b_bcount > bp->b_bufsize)
- panic("bwrite");
- s = splbio();
- bp->b_vp->v_numoutput++;
- splx(s);
- VOP_STRATEGY(bp);
-
- /*
- * If the write was synchronous, then await I/O completion.
- * If the write was "delayed", then we put the buffer on
- * the queue of blocks awaiting I/O completion status.
- */
- if ((flag & B_ASYNC) == 0) {
- error = biowait(bp);
- brelse(bp);
- } else if (flag & B_DELWRI) {
- bp->b_flags |= B_AGE;
- error = 0;
- }
- return (error);
-}
-
-/*
- * Delayed write.
- *
- * The buffer is marked dirty, but is not queued for I/O.
- * This routine should be used when the buffer is expected
- * to be modified again soon, typically a small write that
- * partially fills a buffer.
- *
- * NB: magnetic tapes cannot be delayed; they must be
- * written in the order that the writes are requested.
- */
-bdwrite(bp)
- register struct buf *bp;
-{
-
- if ((bp->b_flags & B_DELWRI) == 0) {
- bp->b_flags |= B_DELWRI;
- reassignbuf(bp, bp->b_vp);
- u.u_ru.ru_oublock++; /* noone paid yet */
- }
- /*
- * If this is a tape drive, the write must be initiated.
- */
- if (bdevsw[major(bp->b_dev)].d_flags & B_TAPE)
- bawrite(bp);
- } else {
- bp->b_flags |= (B_DONE | B_DELWRI);
- brelse(bp);
- }
-}
-
-/*
- * Asynchronous write.
- * Start I/O on a buffer, but do not wait for it to complete.
- * The buffer is released when the I/O completes.
- */
-bawrite(bp)
- register struct buf *bp;
-{
-
- /*
- * Setting the ASYNC flag causes bwrite to return
- * after starting the I/O.
- */
- bp->b_flags |= B_ASYNC;
- (void) bwrite(bp);
-}
-
-/*
- * Release a buffer.
- * Even if the buffer is dirty, no I/O is started.
- */
-brelse(bp)
- register struct buf *bp;
-{
- register struct buf *flist;
- int s;
-
- trace(TR_BRELSE, pack(bp->b_vp, bp->b_bufsize), bp->b_lblkno);
- /*
- * If a process is waiting for the buffer, or
- * is waiting for a free buffer, awaken it.
- */
- if (bp->b_flags & B_WANTED)
- wakeup((caddr_t)bp);
- if (bfreelist[0].b_flags & B_WANTED) {
- bfreelist[0].b_flags &= ~B_WANTED;
- wakeup((caddr_t)bfreelist);
- }
- /*
- * Retry I/O for locked buffers rather than invalidating them.
- */
- if ((bp->b_flags & B_ERROR) && (bp->b_flags & B_LOCKED))
- bp->b_flags &= ~B_ERROR;
- /*
- * Disassociate buffers that are no longer valid.
- */
- if (bp->b_flags & (B_NOCACHE | B_ERROR))
- bp->b_flags |= B_INVAL;
- if ((bp->b_bufsize <= 0) || (bp->b_flags & (B_ERROR | B_INVAL))) {
- if (bp->b_vp)
- brelvp(bp);
- bp->b_flags &= ~B_DELWRI;
- }
- /*
- * Stick the buffer back on a free list.
- */
- s = splbio();
- if (bp->b_bufsize <= 0) {
- /* block has no buffer ... put at front of unused buffer list */
- flist = &bfreelist[BQ_EMPTY];
- binsheadfree(bp, flist);
- } else if (bp->b_flags & (B_ERROR | B_INVAL)) {
- /* block has no info ... put at front of most free list */
- flist = &bfreelist[BQ_AGE];
- binsheadfree(bp, flist);
- } else {
- if (bp->b_flags & B_LOCKED)
- flist = &bfreelist[BQ_LOCKED];
- else if (bp->b_flags & B_AGE)
- flist = &bfreelist[BQ_AGE];
- else
- flist = &bfreelist[BQ_LRU];
- binstailfree(bp, flist);
- }
- bp->b_flags &= ~(B_WANTED | B_BUSY | B_ASYNC | B_AGE | B_NOCACHE);
- splx(s);
-}