+mntinvalbuf(mountp)
+ struct mount *mountp;
+{
+ register struct vnode *vp;
+ int dirty = 0;
+
+ if ((mountp->mnt_flag & MNT_MPBUSY) == 0)
+ panic("mntinvalbuf: not busy");
+loop:
+ for (vp = mountp->mnt_mounth; vp; vp = vp->v_mountf) {
+ if (vget(vp))
+ goto loop;
+ dirty += vinvalbuf(vp, 1);
+ vput(vp);
+ if (vp->v_mount != mountp)
+ goto loop;
+ }
+ 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;