FreeBSD/sys/kern/vfs_bio.c
/*
 *	brelse:
 *
 *	Release a busy buffer and, if requested, free its resources.  The
 *	buffer will be stashed in the appropriate bufqueue[] allowing it
 *	to be accessed later as a cache entity or reused for other purposes.
 */
Release a busy buffer and, if requested, free its resources.  The
buffer will be stashed in the appropriate bufqueue[] allowing it
to be accessed later as a cache entity or reused for other purposes.
Release a busy buffer and if requested free its resources . The buffer will be stashed in the appropriate bufqueue [] allowing it to be accessed later as a cache entity or reused for other purposes .
void
brelse(struct buf *bp)
{
	int qindex;
	if (bp == NULL)
		return;
	CTR3(KTR_BUF, "brelse(%p) vp %p flags %X",
	    bp, bp->b_vp, bp->b_flags);
	KASSERT(!(bp->b_flags & (B_CLUSTER|B_PAGING)),
	    ("brelse: inappropriate B_PAGING or B_CLUSTER bp %p", bp));
	KASSERT((bp->b_flags & B_VMIO) != 0 || (bp->b_flags & B_NOREUSE) == 0,
	    ("brelse: non-VMIO buffer marked NOREUSE"));
	if (BUF_LOCKRECURSED(bp)) {
		BUF_UNLOCK(bp);
		return;
	}
	if (bp->b_flags & B_MANAGED) {
		bqrelse(bp);
		return;
	}
	if ((bp->b_vflags & (BV_BKGRDINPROG | BV_BKGRDERR)) == BV_BKGRDERR) {
		BO_LOCK(bp->b_bufobj);
		bp->b_vflags &= ~BV_BKGRDERR;
		BO_UNLOCK(bp->b_bufobj);
		bdirty(bp);
	}
	if (bp->b_iocmd == BIO_WRITE && (bp->b_ioflags & BIO_ERROR) &&
	    !(bp->b_flags & B_INVAL)) {
		bp->b_ioflags &= ~BIO_ERROR;
		bdirty(bp);
	} else if ((bp->b_flags & (B_NOCACHE | B_INVAL)) ||
	    (bp->b_ioflags & BIO_ERROR) || (bp->b_bufsize <= 0)) {
		bp->b_flags |= B_INVAL;
		if (!LIST_EMPTY(&bp->b_dep))
			buf_deallocate(bp);
		if (bp->b_flags & B_DELWRI)
			bdirtysub();
		bp->b_flags &= ~(B_DELWRI | B_CACHE);
		if ((bp->b_flags & B_VMIO) == 0) {
			allocbuf(bp, 0);
			if (bp->b_vp)
				brelvp(bp);
		}
	}
	if (bp->b_flags & B_DELWRI)
		bp->b_flags &= ~B_RELBUF;
	if ((bp->b_flags & B_VMIO) && (bp->b_flags & B_NOCACHE ||
	    (bp->b_ioflags & BIO_ERROR && bp->b_iocmd == BIO_READ)) &&
	    !(bp->b_vp->v_mount != NULL &&
	    (bp->b_vp->v_mount->mnt_vfc->vfc_flags & VFCF_NETWORK) != 0 &&
	    !vn_isdisk(bp->b_vp, NULL) && (bp->b_flags & B_DELWRI))) {
		vfs_vmio_invalidate(bp);
		allocbuf(bp, 0);
	}
	if ((bp->b_flags & (B_INVAL | B_RELBUF)) != 0 ||
	    (bp->b_flags & (B_DELWRI | B_NOREUSE)) == B_NOREUSE) {
		allocbuf(bp, 0);
		bp->b_flags &= ~B_NOREUSE;
		if (bp->b_vp != NULL)
			brelvp(bp);
	}
	if (bp->b_bufsize == 0 || (bp->b_ioflags & BIO_ERROR) != 0 ||
	    (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF)) != 0)
		bp->b_flags |= B_INVAL;
	if (bp->b_flags & B_INVAL) {
		if (bp->b_flags & B_DELWRI)
			bundirty(bp);
		if (bp->b_vp)
			brelvp(bp);
	}
	if (bp->b_bufsize == 0) {
		buf_free(bp);
		return;
	}
	if (bp->b_flags & (B_INVAL | B_NOCACHE | B_RELBUF) ||
	    (bp->b_ioflags & BIO_ERROR)) {
		bp->b_xflags &= ~(BX_BKGRDWRITE | BX_ALTDATA);
		if (bp->b_vflags & BV_BKGRDINPROG)
			panic("losing buffer 2");
		qindex = QUEUE_CLEAN;
		bp->b_flags |= B_AGE;
	} else if (bp->b_flags & B_DELWRI)
		qindex = QUEUE_DIRTY;
	else
		qindex = QUEUE_CLEAN;
	binsfree(bp, qindex);
	bp->b_flags &= ~(B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF | B_DIRECT);
	if ((bp->b_flags & B_DELWRI) == 0 && (bp->b_xflags & BX_VNDIRTY))
		panic("brelse: not dirty");
	BUF_UNLOCK(bp);
	if (qindex == QUEUE_CLEAN)
		bufspace_wakeup();
}
void brelse ( struct buf * bp ) { int qindex ; if ( bp == NULL ) return ; CTR3 ( KTR_BUF , " " , bp , bp -> b_vp , bp -> b_flags ) ; KASSERT ( ! ( bp -> b_flags & ( B_CLUSTER | B_PAGING ) ) , ( " " , bp ) ) ; KASSERT ( ( bp -> b_flags & B_VMIO ) != 0 || ( bp -> b_flags & B_NOREUSE ) == 0 , ( " " ) ) ; if ( BUF_LOCKRECURSED ( bp ) ) { BUF_UNLOCK ( bp ) ; return ; } if ( bp -> b_flags & B_MANAGED ) { bqrelse ( bp ) ; return ; } if ( ( bp -> b_vflags & ( BV_BKGRDINPROG | BV_BKGRDERR ) ) == BV_BKGRDERR ) { BO_LOCK ( bp -> b_bufobj ) ; bp -> b_vflags &= ~ BV_BKGRDERR ; BO_UNLOCK ( bp -> b_bufobj ) ; bdirty ( bp ) ; } if ( bp -> b_iocmd == BIO_WRITE && ( bp -> b_ioflags & BIO_ERROR ) && ! ( bp -> b_flags & B_INVAL ) ) { bp -> b_ioflags &= ~ BIO_ERROR ; bdirty ( bp ) ; } else if ( ( bp -> b_flags & ( B_NOCACHE | B_INVAL ) ) || ( bp -> b_ioflags & BIO_ERROR ) || ( bp -> b_bufsize <= 0 ) ) { bp -> b_flags |= B_INVAL ; if ( ! LIST_EMPTY ( & bp -> b_dep ) ) buf_deallocate ( bp ) ; if ( bp -> b_flags & B_DELWRI ) bdirtysub ( ) ; bp -> b_flags &= ~ ( B_DELWRI | B_CACHE ) ; if ( ( bp -> b_flags & B_VMIO ) == 0 ) { allocbuf ( bp , 0 ) ; if ( bp -> b_vp ) brelvp ( bp ) ; } } if ( bp -> b_flags & B_DELWRI ) bp -> b_flags &= ~ B_RELBUF ; if ( ( bp -> b_flags & B_VMIO ) && ( bp -> b_flags & B_NOCACHE || ( bp -> b_ioflags & BIO_ERROR && bp -> b_iocmd == BIO_READ ) ) && ! ( bp -> b_vp -> v_mount != NULL && ( bp -> b_vp -> v_mount -> mnt_vfc -> vfc_flags & VFCF_NETWORK ) != 0 && ! vn_isdisk ( bp -> b_vp , NULL ) && ( bp -> b_flags & B_DELWRI ) ) ) { vfs_vmio_invalidate ( bp ) ; allocbuf ( bp , 0 ) ; } if ( ( bp -> b_flags & ( B_INVAL | B_RELBUF ) ) != 0 || ( bp -> b_flags & ( B_DELWRI | B_NOREUSE ) ) == B_NOREUSE ) { allocbuf ( bp , 0 ) ; bp -> b_flags &= ~ B_NOREUSE ; if ( bp -> b_vp != NULL ) brelvp ( bp ) ; } if ( bp -> b_bufsize == 0 || ( bp -> b_ioflags & BIO_ERROR ) != 0 || ( bp -> b_flags & ( B_INVAL | B_NOCACHE | B_RELBUF ) ) != 0 ) bp -> b_flags |= B_INVAL ; if ( bp -> b_flags & B_INVAL ) { if ( bp -> b_flags & B_DELWRI ) bundirty ( bp ) ; if ( bp -> b_vp ) brelvp ( bp ) ; } if ( bp -> b_bufsize == 0 ) { buf_free ( bp ) ; return ; } if ( bp -> b_flags & ( B_INVAL | B_NOCACHE | B_RELBUF ) || ( bp -> b_ioflags & BIO_ERROR ) ) { bp -> b_xflags &= ~ ( BX_BKGRDWRITE | BX_ALTDATA ) ; if ( bp -> b_vflags & BV_BKGRDINPROG ) panic ( " " ) ; qindex = QUEUE_CLEAN ; bp -> b_flags |= B_AGE ; } else if ( bp -> b_flags & B_DELWRI ) qindex = QUEUE_DIRTY ; else qindex = QUEUE_CLEAN ; binsfree ( bp , qindex ) ; bp -> b_flags &= ~ ( B_ASYNC | B_NOCACHE | B_AGE | B_RELBUF | B_DIRECT ) ; if ( ( bp -> b_flags & B_DELWRI ) == 0 && ( bp -> b_xflags & BX_VNDIRTY ) ) panic ( " " ) ; BUF_UNLOCK ( bp ) ; if ( qindex == QUEUE_CLEAN ) bufspace_wakeup ( ) ; }
brelse:
      Release a busy buffer and, if requested, free its resources.
brelse : Release a busy buffer and if requested free its resources .
/*
	 * Many functions erroneously call brelse with a NULL bp under rare
	 * error conditions. Simply return when called with a NULL bp.
	 */ /*
		 * Do not process, in particular, do not handle the
		 * B_INVAL/B_RELBUF and do not release to free list.
		 */ /*
		 * Failed write, redirty.  Must clear BIO_ERROR to prevent
		 * pages from being scrapped.
		 */ /*
		 * Either a failed read I/O or we were asked to free or not
		 * cache the buffer.
		 */ /*
	 * We must clear B_RELBUF if B_DELWRI is set.  If vfs_vmio_truncate() 
	 * is called with B_DELWRI set, the underlying pages may wind up
	 * getting freed causing a previous write (bdwrite()) to get 'lost'
	 * because pages associated with a B_DELWRI bp are marked clean.
	 * 
	 * We still allow the B_INVAL case to call vfs_vmio_truncate(), even
	 * if B_DELWRI is set.
	 */ /*
	 * VMIO buffer rundown.  It is not very necessary to keep a VMIO buffer
	 * constituted, not even NFS buffers now.  Two flags effect this.  If
	 * B_INVAL, the struct buf is invalidated but the VM object is kept
	 * around ( i.e. so it is trivial to reconstitute the buffer later ).
	 *
	 * If BIO_ERROR or B_NOCACHE is set, pages in the VM object will be
	 * invalidated.  BIO_ERROR cannot be set for a failed write unless the
	 * buffer is also B_INVAL because it hits the re-dirtying code above.
	 *
	 * Normally we can do this whether a buffer is B_DELWRI or not.  If
	 * the buffer is an NFS buffer, it is tracking piecemeal writes or
	 * the commit state and we cannot afford to lose the buffer. If the
	 * buffer has a background write in progress, we need to keep it
	 * around to prevent it from being reconstituted and starting a second
	 * background write.
	 */ /*
	 * If the buffer has junk contents signal it and eventually
	 * clean up B_DELWRI and diassociate the vnode so that gbincore()
	 * doesn't find it.
	 */ /* buffers with no memory */ /* buffers with junk contents */ /* remaining buffers */ /* unlock */