FreeBSD/sys/ufs/ffs/ffs_vfsops.c
/*
 * Write, release buffer on completion.  (Done by iodone
 * if async).  Do not bother writing anything if the buffer
 * is invalid.
 *
 * Note that we set B_CACHE here, indicating that buffer is
 * fully valid and thus cacheable.  This is true even of NFS
 * now so we set it generally.  This could be set either here
 * or in biodone() since the I/O is synchronous.  We put it
 * here.
 */
Write, release buffer on completion.  (Done by iodone
if async).  Do not bother writing anything if the buffer
is invalid.

Note that we set B_CACHE here, indicating that buffer is
fully valid and thus cacheable.  This is true even of NFS
now so we set it generally.  This could be set either here
or in biodone() since the I/O is synchronous.  We put it
here.
Write release buffer on completion . ( Done by iodone if async ) . Do not bother writing anything if the buffer is invalid . Note that we set B_CACHE here indicating that buffer is fully valid and thus cacheable . This is true even of NFS now so we set it generally . This could be set either here or in biodone () since the I / O is synchronous . We put it here .
static int
ffs_bufwrite(struct buf *bp)
{
	struct buf *newbp;
	CTR3(KTR_BUF, "bufwrite(%p) vp %p flags %X", bp, bp->b_vp, bp->b_flags);
	if (bp->b_flags & B_INVAL) {
		brelse(bp);
		return (0);
	}
	if (!BUF_ISLOCKED(bp))
		panic("bufwrite: buffer is not busy???");
	BO_LOCK(bp->b_bufobj);
	if (bp->b_vflags & BV_BKGRDINPROG) {
		if (bp->b_flags & B_ASYNC) {
			BO_UNLOCK(bp->b_bufobj);
			bdwrite(bp);
			return (0);
		}
		bp->b_vflags |= BV_BKGRDWAIT;
		msleep(&bp->b_xflags, BO_LOCKPTR(bp->b_bufobj), PRIBIO,
		    "bwrbg", 0);
		if (bp->b_vflags & BV_BKGRDINPROG)
			panic("bufwrite: still writing");
	}
	bp->b_vflags &= ~BV_BKGRDERR;
	BO_UNLOCK(bp->b_bufobj);
	if (dobkgrdwrite && (bp->b_xflags & BX_BKGRDWRITE) &&
	    (bp->b_flags & B_ASYNC) &&
	    !vm_page_count_severe() &&
	    !buf_dirty_count_severe()) {
		KASSERT(bp->b_iodone == NULL,
		    ("bufwrite: needs chained iodone (%p)", bp->b_iodone));
		newbp = geteblk(bp->b_bufsize, GB_NOWAIT_BD);
		if (newbp == NULL)
			goto normal_write;
		KASSERT(buf_mapped(bp), ("Unmapped cg"));
		memcpy(newbp->b_data, bp->b_data, bp->b_bufsize);
		BO_LOCK(bp->b_bufobj);
		bp->b_vflags |= BV_BKGRDINPROG;
		BO_UNLOCK(bp->b_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
		if (LIST_EMPTY(&bp->b_dep) ||
		    softdep_move_dependencies(bp, newbp) == 0)
			bundirty(bp);
#else
		bundirty(bp);
#endif
		bqrelse(bp);
		bp = newbp;
	} else
		bundirty(bp);
normal_write:
	return (bufwrite(bp));
}
static int ffs_bufwrite ( struct buf * bp ) { struct buf * newbp ; CTR3 ( KTR_BUF , " " , bp , bp -> b_vp , bp -> b_flags ) ; if ( bp -> b_flags & B_INVAL ) { brelse ( bp ) ; return ( 0 ) ; } if ( ! BUF_ISLOCKED ( bp ) ) panic ( " " ) ; BO_LOCK ( bp -> b_bufobj ) ; if ( bp -> b_vflags & BV_BKGRDINPROG ) { if ( bp -> b_flags & B_ASYNC ) { BO_UNLOCK ( bp -> b_bufobj ) ; bdwrite ( bp ) ; return ( 0 ) ; } bp -> b_vflags |= BV_BKGRDWAIT ; msleep ( & bp -> b_xflags , BO_LOCKPTR ( bp -> b_bufobj ) , PRIBIO , " " , 0 ) ; if ( bp -> b_vflags & BV_BKGRDINPROG ) panic ( " " ) ; } bp -> b_vflags &= ~ BV_BKGRDERR ; BO_UNLOCK ( bp -> b_bufobj ) ; if ( dobkgrdwrite && ( bp -> b_xflags & BX_BKGRDWRITE ) && ( bp -> b_flags & B_ASYNC ) && ! vm_page_count_severe ( ) && ! buf_dirty_count_severe ( ) ) { KASSERT ( bp -> b_iodone == NULL , ( " " , bp -> b_iodone ) ) ; newbp = geteblk ( bp -> b_bufsize , GB_NOWAIT_BD ) ; if ( newbp == NULL ) goto normal_write ; KASSERT ( buf_mapped ( bp ) , ( " " ) ) ; memcpy ( newbp -> b_data , bp -> b_data , bp -> b_bufsize ) ; BO_LOCK ( bp -> b_bufobj ) ; bp -> b_vflags |= BV_BKGRDINPROG ; BO_UNLOCK ( bp -> b_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 if ( LIST_EMPTY ( & bp -> b_dep ) || softdep_move_dependencies ( bp , newbp ) == 0 ) bundirty ( bp ) ; #else bundirty ( bp ) ; #endif bqrelse ( bp ) ; bp = newbp ; } else bundirty ( bp ) ; normal_write : return ( bufwrite ( bp ) ) ; }
Write, release buffer on completion.
Write release buffer on completion .
/*
	 * If a background write is already in progress, delay
	 * writing this block if it is asynchronous. Otherwise
	 * wait for the background write to complete.
	 */ /*
	 * If this buffer is marked for background writing and we
	 * do not have to wait for it, make a copy and write the
	 * copy so as to leave this buffer ready for further use.
	 *
	 * This optimization eats a lot of memory.  If we have a page
	 * or buffer shortfall we can't do it.
	 */ /* get a new block */ /*
		 * Move over the dependencies.  If there are rollbacks,
		 * leave the parent buffer dirtied as it will need to
		 * be written again.
		 */ /*
		 * Initiate write on the copy, release the original.  The
		 * BKGRDINPROG flag prevents it from going away until 
		 * the background write completes.
		 */ /* Mark the buffer clean */ /* Let the normal bufwrite do the rest for us */