Use balloc to extend Ifile.
[unix-history] / usr / src / sys / ufs / lfs / lfs_bio.c
index fff6ba7..397c3a8 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_bio.c   7.5 (Berkeley) %G%
+ *     @(#)lfs_bio.c   7.19 (Berkeley) %G%
  */
 
 #include <sys/param.h>
  */
 
 #include <sys/param.h>
@@ -13,6 +13,7 @@
 #include <sys/vnode.h>
 #include <sys/resourcevar.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
 #include <sys/resourcevar.h>
 #include <sys/mount.h>
+#include <sys/kernel.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
 
 #include <ufs/ufs/quota.h>
 #include <ufs/ufs/inode.h>
  * No write cost accounting is done.
  * This is almost certainly wrong for synchronous operations and NFS.
  */
  * No write cost accounting is done.
  * This is almost certainly wrong for synchronous operations and NFS.
  */
+int    lfs_allclean_wakeup;            /* Cleaner wakeup address. */
 int    locked_queue_count;             /* XXX Count of locked-down buffers. */
 int    locked_queue_count;             /* XXX Count of locked-down buffers. */
+int    lfs_writing;                    /* Set if already kicked off a writer
+                                          because of buffer space */
+/*
+#define WRITE_THRESHHOLD       ((nbuf >> 2) - 10)
+#define WAIT_THRESHHOLD                ((nbuf >> 1) - 10)
+*/
+#define WAIT_THRESHHOLD         (nbuf - (nbuf >> 2) - 10)
+#define WRITE_THRESHHOLD        ((nbuf >> 1) - 10)
+#define LFS_BUFWAIT    2
 
 int
 
 int
-lfs_bwrite(bp)
-       register BUF *bp;
+lfs_bwrite(ap)
+       struct vop_bwrite_args /* {
+               struct buf *a_bp;
+       } */ *ap;
 {
 {
-#ifdef VERBOSE
-printf("lfs_bwrite\n");
-#endif
+       register struct buf *bp = ap->a_bp;
+       struct lfs *fs;
+       struct inode *ip;
+       int error, s;
+
        /*
         * Set the delayed write flag and use reassignbuf to move the buffer
         * from the clean list to the dirty one.
        /*
         * Set the delayed write flag and use reassignbuf to move the buffer
         * from the clean list to the dirty one.
@@ -45,12 +60,36 @@ printf("lfs_bwrite\n");
         * the buffer onto the LOCKED free list.  This is necessary, otherwise
         * getnewbuf() would try to reclaim the buffers using bawrite, which
         * isn't going to work.
         * the buffer onto the LOCKED free list.  This is necessary, otherwise
         * getnewbuf() would try to reclaim the buffers using bawrite, which
         * isn't going to work.
+        *
+        * XXX we don't let meta-data writes run out of space because they can
+        * come from the segment writer.  We need to make sure that there is
+        * enough space reserved so that there's room to write meta-data
+        * blocks.
         */
         */
-       if (!(bp->b_flags & B_LOCKED))
+       if (!(bp->b_flags & B_LOCKED)) {
+               fs = VFSTOUFS(bp->b_vp->v_mount)->um_lfs;
+               while (!LFS_FITS(fs, fsbtodb(fs, 1)) && !IS_IFILE(bp) &&
+                   bp->b_lblkno > 0) {
+                       /* Out of space, need cleaner to run */
+                       wakeup(&lfs_allclean_wakeup);
+                       if (error = tsleep(&fs->lfs_avail, PCATCH | PUSER,
+                           "cleaner", NULL)) {
+                               brelse(bp);
+                               return (error);
+                       }
+               }
+               ip = VTOI((bp)->b_vp);
+               if (!(ip->i_flag & IMOD))
+                       ++fs->lfs_uinodes;
+               ip->i_flag |= IMOD | ICHG | IUPD;                       \
+               fs->lfs_avail -= fsbtodb(fs, 1);
                ++locked_queue_count;
                ++locked_queue_count;
-       bp->b_flags |= B_DELWRI | B_LOCKED;
-       bp->b_flags &= ~(B_READ | B_DONE | B_ERROR);
-       reassignbuf(bp, bp->b_vp);
+               bp->b_flags |= B_DELWRI | B_LOCKED;
+               bp->b_flags &= ~(B_READ | B_ERROR);
+               s = splbio();
+               reassignbuf(bp, bp->b_vp);
+               splx(s);
+       }
        brelse(bp);
        return (0);
 }
        brelse(bp);
        return (0);
 }
@@ -67,27 +106,58 @@ void
 lfs_flush()
 {
        register struct mount *mp;
 lfs_flush()
 {
        register struct mount *mp;
-       struct mount *omp;
 
 
-       /* 1M in a 4K file system. */
-       if (locked_queue_count < 256)
+#ifdef DOSTATS
+       ++lfs_stats.write_exceeded;
+#endif
+       if (lfs_writing)
                return;
                return;
+       lfs_writing = 1;
        mp = rootfs;
        do {
        mp = rootfs;
        do {
-               /*
-                * The lock check below is to avoid races with mount
-                * and unmount.
-                */
+               /* The lock check below is to avoid races with unmount. */
                if (mp->mnt_stat.f_type == MOUNT_LFS &&
                if (mp->mnt_stat.f_type == MOUNT_LFS &&
-                   (mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_MPBUSY)) == 0 &&
-                   !vfs_busy(mp)) {
+                   (mp->mnt_flag & (MNT_MLOCK|MNT_RDONLY|MNT_UNMOUNT)) == 0 &&
+                   !((((struct ufsmount *)mp->mnt_data))->ufsmount_u.lfs)->lfs_dirops ) {
+                       /*
+                        * We set the queue to 0 here because we are about to
+                        * write all the dirty buffers we have.  If more come
+                        * in while we're writing the segment, they may not
+                        * get written, so we want the count to reflect these
+                        * new writes after the segwrite completes.
+                        */
+#ifdef DOSTATS
+                       ++lfs_stats.flush_invoked;
+#endif
                        lfs_segwrite(mp, 0);
                        lfs_segwrite(mp, 0);
-                       omp = mp;
-                       mp = mp->mnt_next;
-                       vfs_unbusy(omp);
-                       /* Not exact, but it doesn't matter. */
-                       locked_queue_count = 0;
-               } else
-                       mp = mp->mnt_next;
+               }
+               mp = mp->mnt_next;
        } while (mp != rootfs);
        } while (mp != rootfs);
+       lfs_writing = 0;
+}
+
+int
+lfs_check(vp, blkno)
+       struct vnode *vp;
+       daddr_t blkno;
+{
+       extern int lfs_allclean_wakeup;
+       int error;
+
+       error = 0;
+       if (incore(vp, blkno))
+               return (0);
+       if (locked_queue_count > WRITE_THRESHHOLD)
+               lfs_flush();
+
+       /* If out of buffers, wait on writer */
+       while (locked_queue_count > WAIT_THRESHHOLD) {
+#ifdef DOSTATS
+           ++lfs_stats.wait_exceeded;
+#endif
+           error = tsleep(&locked_queue_count, PCATCH | PUSER, "buffers",
+               hz * LFS_BUFWAIT);
+       }
+
+       return (error);
 }
 }