+ return (dirty);
+}
+
+/*
+ * Flush out and invalidate all buffers associated with a vnode.
+ * Called with the underlying object locked.
+ */
+vinvalbuf(vp, save)
+ register struct vnode *vp;
+ int save;
+{
+ register struct buf *bp;
+ struct buf *nbp, *blist;
+ int s, dirty = 0;
+
+ for (;;) {
+ if (blist = vp->v_dirtyblkhd)
+ /* void */;
+ else if (blist = vp->v_cleanblkhd)
+ /* void */;
+ else
+ break;
+ for (bp = blist; bp; bp = nbp) {
+ nbp = bp->b_blockf;
+ s = splbio();
+ if (bp->b_flags & B_BUSY) {
+ bp->b_flags |= B_WANTED;
+ sleep((caddr_t)bp, PRIBIO + 1);
+ splx(s);
+ break;
+ }
+ bremfree(bp);
+ bp->b_flags |= B_BUSY;
+ splx(s);
+ if (save && (bp->b_flags & B_DELWRI)) {
+ dirty++;
+ (void) bwrite(bp);
+ break;
+ }
+ if (bp->b_vp != vp)
+ reassignbuf(bp, bp->b_vp);
+ else
+ bp->b_flags |= B_INVAL;
+ brelse(bp);
+ }
+ }
+ if (vp->v_dirtyblkhd || vp->v_cleanblkhd)
+ panic("vinvalbuf: flush failed");
+ return (dirty);
+}
+
+/*
+ * Associate a buffer with a vnode.
+ */
+bgetvp(vp, bp)
+ register struct vnode *vp;
+ register struct buf *bp;
+{
+ register struct vnode *vq;
+ register struct buf *bq;
+
+ if (bp->b_vp)
+ panic("bgetvp: not free");
+ VHOLD(vp);
+ bp->b_vp = vp;
+ if (vp->v_type == VBLK || vp->v_type == VCHR)
+ bp->b_dev = vp->v_rdev;
+ else
+ bp->b_dev = NODEV;
+ /*
+ * Insert onto list for new vnode.
+ */
+ if (bq = vp->v_cleanblkhd)
+ bq->b_blockb = &bp->b_blockf;
+ bp->b_blockf = bq;
+ bp->b_blockb = &vp->v_cleanblkhd;
+ vp->v_cleanblkhd = bp;
+}
+
+/*
+ * Disassociate a buffer from a vnode.
+ */
+brelvp(bp)
+ register struct buf *bp;
+{
+ struct buf *bq;
+ struct vnode *vp;
+
+ if (bp->b_vp == (struct vnode *) 0)
+ panic("brelvp: NULL");
+ /*
+ * Delete from old vnode list, if on one.
+ */
+ if (bp->b_blockb) {
+ if (bq = bp->b_blockf)
+ bq->b_blockb = bp->b_blockb;
+ *bp->b_blockb = bq;
+ bp->b_blockf = NULL;
+ bp->b_blockb = NULL;
+ }
+ vp = bp->b_vp;
+ bp->b_vp = (struct vnode *) 0;
+ HOLDRELE(vp);
+}
+
+/*
+ * Reassign a buffer from one vnode to another.
+ * Used to assign file specific control information
+ * (indirect blocks) to the vnode to which they belong.
+ */
+reassignbuf(bp, newvp)
+ register struct buf *bp;
+ register struct vnode *newvp;
+{
+ register struct buf *bq, **listheadp;
+
+ if (newvp == NULL)
+ panic("reassignbuf: NULL");
+ /*
+ * Delete from old vnode list, if on one.
+ */
+ if (bp->b_blockb) {
+ if (bq = bp->b_blockf)
+ bq->b_blockb = bp->b_blockb;
+ *bp->b_blockb = bq;
+ }
+ /*
+ * If dirty, put on list of dirty buffers;
+ * otherwise insert onto list of clean buffers.
+ */
+ if (bp->b_flags & B_DELWRI)
+ listheadp = &newvp->v_dirtyblkhd;
+ else
+ listheadp = &newvp->v_cleanblkhd;
+ if (bq = *listheadp)
+ bq->b_blockb = &bp->b_blockf;
+ bp->b_blockf = bq;
+ bp->b_blockb = listheadp;
+ *listheadp = bp;