checkpoint
[unix-history] / usr / src / sys / ufs / lfs / lfs_segment.c
index b9efcf1..baf38c6 100644 (file)
@@ -4,9 +4,10 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_segment.c       5.1 (Berkeley) %G%
+ *     @(#)lfs_segment.c       5.2 (Berkeley) %G%
  */
 
  */
 
+#ifdef LOGFS
 #include "param.h"
 #include "systm.h"
 #include "namei.h"
 #include "param.h"
 #include "systm.h"
 #include "namei.h"
 #include "lfs_extern.h"
 
 /*
 #include "lfs_extern.h"
 
 /*
-Need to write the inodes out.
-The indirect buffers need to be marked dirty
-What about sync?  How do you wait on the last I/O?
-Need to keep vnode v_numoutput up to date for pending writes.
+Add a check so that if the segment is empty, you don't write it.
+Write the code with lfs_ialloc to allocate a new page of inodes if you have to.
+Make an incoming sync wait until the previous one finishes.  Keith
+       will write this.  When this happens, we no longer have to be
+       able to chain superblocks together and handle multiple segments
+       writing -- Seems like we can call biowait to wait for an io.
+       However, I don't think we want to wait on the summary I/O
+       necessarily, because if we've got lots of dirty buffers piling
+       up, it would be nice to process them and get the segment all
+       ready to write.  Perhaps we can just wait before firing up the
+       next set of writes, rather than waiting to start doing anything.
+       Also -- my lfs_writesuper should wait until all the segment writes
+       are done (I added a biowait, but we need to make sure that the SEGMENT
+       structure hasn't been freed before we get there).
+Need to keep vnode v_numoutput up to date for pending writes?
+???Could actually fire off the datablock writes before you finish.  This
+would give them a chance to get started earlier...
 */
 
 static int      lfs_biocallback __P((BUF *));
 static void     lfs_endsum __P((LFS *, SEGMENT *, int));
 */
 
 static int      lfs_biocallback __P((BUF *));
 static void     lfs_endsum __P((LFS *, SEGMENT *, int));
+static SEGMENT *lfs_gather
+                   __P((LFS *, SEGMENT *, VNODE *, int (*) __P((BUF *))));
 static BUF     *lfs_newbuf __P((LFS *, daddr_t, size_t));
 static SEGMENT *lfs_newseg __P((LFS *));
 static void     lfs_newsum __P((LFS *, SEGMENT *));
 static daddr_t  lfs_nextseg __P((LFS *));
 static BUF     *lfs_newbuf __P((LFS *, daddr_t, size_t));
 static SEGMENT *lfs_newseg __P((LFS *));
 static void     lfs_newsum __P((LFS *, SEGMENT *));
 static daddr_t  lfs_nextseg __P((LFS *));
-static int      lfs_updatemeta __P((LFS *, INODE *, FINFO *, BUF **));
-static SEGMENT *lfs_writefile __P((SEGMENT *, LFS *, VNODE *));
-static void     lfs_writemeta __P((void));
+static void     lfs_updatemeta __P((LFS *, SEGMENT *, INODE *, daddr_t *, 
+                    BUF **, int));
+static void     lfs_writeckp __P((LFS *, SEGMENT *));
+static SEGMENT *lfs_writefile __P((SEGMENT *, LFS *, VNODE *, int));
+static SEGMENT *lfs_writeinode __P((LFS *, SEGMENT *, VNODE *));
 static void     lfs_writeseg __P((LFS *, SEGMENT *));
 static void     lfs_writeseg __P((LFS *, SEGMENT *));
-static void     shellsort __P((BUF **, u_long *, register int));
+static void     lfs_writesuper __P((LFS *, SEGMENT *));
+static int      match_data __P((BUF *));
+static int      match_dindir __P((BUF *));
+static int      match_indir __P((BUF *));
+static void     shellsort __P((BUF **, daddr_t *, register int));
 
 /*
  * XXX -- when we add fragments in here, we will need to allocate a larger
  * buffer pointer array (sp->bpp).
  */
 int
 
 /*
  * XXX -- when we add fragments in here, we will need to allocate a larger
  * buffer pointer array (sp->bpp).
  */
 int
-lfs_segwrite(mp)
+lfs_segwrite(mp, do_ckp)
        MOUNT *mp;
        MOUNT *mp;
+       int do_ckp;                     /* do a checkpoint too */
 {
        FINFO *fip;                     /* current file info structure */
        INODE *ip;
 {
        FINFO *fip;                     /* current file info structure */
        INODE *ip;
@@ -63,9 +86,7 @@ lfs_segwrite(mp)
        VNODE *vp;
        SEGMENT *sp;
 
        VNODE *vp;
        SEGMENT *sp;
 
-printf("lfs_segwrite: %s %s\n", mp->mnt_stat.f_mntonname, mp->mnt_stat.f_mntfromname);
        fs = VFSTOUFS(mp)->um_lfs;
        fs = VFSTOUFS(mp)->um_lfs;
-
        sp = lfs_newseg(fs);
 loop:
        for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
        sp = lfs_newseg(fs);
 loop:
        for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
@@ -73,7 +94,6 @@ loop:
                 * If the vnode that we are about to sync is no longer
                 * associated with this mount point, start over.
                 */
                 * If the vnode that we are about to sync is no longer
                 * associated with this mount point, start over.
                 */
-printf("lfs_segwrite: processing inum %d\n", VTOI(vp)->i_number);
                if (vp->v_mount != mp)
                        goto loop;
                if (VOP_ISLOCKED(vp))
                if (vp->v_mount != mp)
                        goto loop;
                if (VOP_ISLOCKED(vp))
@@ -86,18 +106,16 @@ printf("lfs_segwrite: processing inum %d\n", VTOI(vp)->i_number);
                        continue;
                if (vget(vp))
                        goto loop;
                        continue;
                if (vget(vp))
                        goto loop;
-               sp = lfs_writefile(sp, fs, vp);
-
-               /* Need to take care of inode now */
-printf("lfs_segwrite: need to add dinode %d to seg\n", ip->i_din.di_inum);
+               sp = lfs_writefile(sp, fs, vp, do_ckp);
                vput(vp);
        }
                vput(vp);
        }
-       /*
-        * Force stale file system control information to be flushed.
-        */
-       lfs_writeseg(fs, sp);
-/*     vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); */
-printf("lfs_segwrite: returning from segwrite\n");
+       if (do_ckp)
+               lfs_writeckp(fs, sp);
+       else
+               lfs_writeseg(fs, sp);
+#ifdef NOTLFS
+       vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
+#endif
        return (0);
 }
 
        return (0);
 }
 
@@ -110,25 +128,45 @@ lfs_biocallback(bp)
        UFSMOUNT *ump;
        VNODE *devvp;
 
        UFSMOUNT *ump;
        VNODE *devvp;
 
+       /*
+        * Grab the mount point for later (used to find the file system and
+        * block device) and, if the contents are valid, move the buffer back
+        * onto the clean list.
+        */
+printf("lfs_biocallback: buffer %x\n", bp, bp->b_lblkno);
        ump = VFSTOUFS(bp->b_vp->v_mount);
        ump = VFSTOUFS(bp->b_vp->v_mount);
+       if (bp->b_flags & B_NOCACHE)
+               bp->b_vp = NULL;
+       else {
+               bp->b_flags &= ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
+               reassignbuf(bp, bp->b_vp);
+       }
+
        fs = ump->um_lfs;
        devvp = ump->um_devvp;
        fs = ump->um_lfs;
        devvp = ump->um_devvp;
-                                                       /* XXX splbio(); */
-printf("lfs_biocallback: iocount: %d\n", fs->lfs_iocount);
-       if (--fs->lfs_iocount) {
+       brelse(bp);             /* move up... XXX */
+
+printf("\nlfs_biocallback: iocount %d\n", fs->lfs_iocount);
+       if (fs->lfs_iocount == 0) {
+               /* Wake up any other syncs waiting on this file system. */
+               return;
+       }
+       --fs->lfs_iocount;
+       if (fs->lfs_iocount == 0) {
+printf("\nlfs_biocallback: doing summary write\n");
                /* Fire off summary writes */
                for (sp = fs->lfs_seglist; sp; sp = next_sp) {
                        next_sp = sp->nextp;
                /* Fire off summary writes */
                for (sp = fs->lfs_seglist; sp; sp = next_sp) {
                        next_sp = sp->nextp;
-                       (*(devvp->v_op->vop_strategy))(*(sp->cbpp - 1));
-printf("free: segsum %x bpp %x sp %x\n", sp->segsum, sp->bpp, sp);
-                       free(sp->segsum, M_SEGMENT);
+#ifdef MOVETONEWBUF
+                       (*(sp->cbpp - 1))->b_dev = bp->b_dev;
+#endif
+                       (devvp->v_op->vop_strategy)(*(sp->cbpp - 1));
                        free(sp->bpp, M_SEGMENT);
                        free(sp, M_SEGMENT);
                }
        }
 }
 
                        free(sp->bpp, M_SEGMENT);
                        free(sp, M_SEGMENT);
                }
        }
 }
 
-
 static void
 lfs_endsum(fs, sp, calc_next)
        LFS *fs;
 static void
 lfs_endsum(fs, sp, calc_next)
        LFS *fs;
@@ -138,50 +176,117 @@ lfs_endsum(fs, sp, calc_next)
        BUF *bp;
        SEGSUM *ssp;
        daddr_t next_addr;
        BUF *bp;
        SEGSUM *ssp;
        daddr_t next_addr;
-       int npages, nseg_pages;
+       int npages, nseg_pages, nsums_per_blk;
+
+/* printf("lfs_endsum\n");             /**/
+       if (sp->sbp == NULL)
+               return;
 
 
-printf("lfs_endsum\n");
        ssp = sp->segsum;
        if (!calc_next)
                ssp->ss_nextsum = (daddr_t) -1;
        ssp = sp->segsum;
        if (!calc_next)
                ssp->ss_nextsum = (daddr_t) -1;
+       else
+               ssp->ss_nextsum = sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE;
 
 
-       nseg_pages = sp->sum_num / (fs->lfs_bsize / LFS_SUMMARY_SIZE);
-       if ((sp->sum_num % (fs->lfs_bsize / LFS_SUMMARY_SIZE)) == 0) {
+       if ((sp->sum_num % (fs->lfs_bsize / LFS_SUMMARY_SIZE)) == (nsums_per_blk - 1)) {
                /*
                /*
-                * May need to change the nextsum field on the previous
-                * summary header in which case we need to recompute the
-                * checksum as well.
+                * This buffer is now full.  Compute the next address if appropriate
+                * and the checksum, and close the buffer by setting sp->sbp NULL.
                 */
                 */
-               npages = nseg_pages + (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
-               next_addr = fs->lfs_sboffs[0] + 
-                   (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize)
-                   - fsbtodb(fs, npages) - LFS_SUMMARY_SIZE / DEV_BSIZE;
-               if (calc_next)
+               if (calc_next) {
+                       nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+                       nseg_pages = 1 + sp->sum_num / nsums_per_blk;
+                       npages = nseg_pages + (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
+                       next_addr = fs->lfs_sboffs[0] + 
+                           (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize)
+                           - fsbtodb(fs, (npages - 1)) - LFS_SUMMARY_SIZE / DEV_BSIZE;
                        ssp->ss_nextsum = next_addr;
                        ssp->ss_nextsum = next_addr;
-               ssp->ss_cksum = cksum(&ssp->ss_cksum, 
-                   LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
-               bp = lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize);
-               bcopy(sp->segsum, bp->b_un.b_words, fs->lfs_bsize);
-               bp->b_flags |= B_BUSY;
-               if (nseg_pages != 1) {
-                       bp->b_flags |= B_CALL;
-                       bp->b_iodone = lfs_biocallback;
                }
                }
-               brelse(bp);
-               sp->bpp[fs->lfs_ssize - npages] = bp;
-               sp->segsum = (SEGSUM *)(sp->segsum + fs->lfs_bsize - 
-                   LFS_SUMMARY_SIZE);
-               sp->sum_addr = next_addr;
-       } else {
-               sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE;
-               ssp->ss_nextsum = sp->sum_addr;
+               ssp->ss_cksum = cksum(&ssp->ss_cksum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
+               sp->sbp = NULL;
+       } else
                /* Calculate cksum on previous segment summary */
                ssp->ss_cksum = cksum(&ssp->ss_cksum, 
                    LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
                /* Calculate cksum on previous segment summary */
                ssp->ss_cksum = cksum(&ssp->ss_cksum, 
                    LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
-               sp->segsum -= LFS_SUMMARY_SIZE;
+}
+
+static SEGMENT *
+lfs_gather(fs, sp, vp, match)
+       LFS *fs;
+       SEGMENT *sp;
+       VNODE *vp;
+       int (*match) __P((BUF *));
+{
+       BUF **bpp, *bp, *nbp;
+       FINFO *fip;
+       INODE *ip;
+       int count, s, version;
+       daddr_t *lbp, *start_lbp;
+
+       ip = VTOI(vp);
+       bpp = sp->cbpp;
+       fip = sp->fip;
+       version = fip->fi_version;
+       start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks];
+       count = 0;
+
+       s = splbio();
+       for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
+               nbp = bp->b_blockf;
+               if ((bp->b_flags & B_BUSY))
+                       continue;
+               if ((bp->b_flags & B_DELWRI) == 0)
+                       panic("lfs_write: not dirty");
+               if (!match(bp))
+                       continue;
+               bremfree(bp);
+               bp->b_flags |= B_BUSY | B_CALL;
+               bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev;
+               bp->b_iodone = lfs_biocallback;
+
+               *lbp++ = bp->b_lblkno;
+               *sp->cbpp++ = bp;
+               fip->fi_nblocks++;
+               sp->sum_bytes_left -= sizeof(daddr_t);
+               sp->seg_bytes_left -= bp->b_bufsize;
+               if (sp->sum_bytes_left < sizeof(daddr_t) || 
+                   sp->seg_bytes_left < fs->lfs_bsize) {
+                       /*
+                        * We are about to allocate a new summary block
+                        * and possibly a new segment.  So, we need to
+                        * sort the blocks we've done so far, and assign
+                        * the disk addresses, so we can start a new block
+                        * correctly.  We may be doing I/O so we need to
+                        * release the s lock before doing anything.
+                        */
+                       splx(s);
+                       lfs_updatemeta(fs, sp, ip, start_lbp, bpp,
+                           lbp - start_lbp);
+
+                       /* Put this file in the segment summary */
+                       ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
+
+                       if (sp->seg_bytes_left < fs->lfs_bsize) {
+                               lfs_writeseg(fs, sp);
+                               sp = lfs_newseg(fs);
+                       } else if (sp->sum_bytes_left < sizeof(daddr_t))
+                               lfs_newsum(fs, sp);
+                       fip = sp->fip;
+                       fip->fi_ino = ip->i_number;
+                       fip->fi_version = version;
+                       bpp = sp->cbpp;
+                       /* You know that you have a new FINFO either way */
+                       start_lbp = lbp = fip->fi_blocks;
+                       s = splbio();
+               }
        }
        }
+       splx(s);
+       lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp);
+
+       return(sp);
 }
 
 }
 
+
 static BUF *
 lfs_newbuf(fs, daddr, size)
        LFS *fs;
 static BUF *
 lfs_newbuf(fs, daddr, size)
        LFS *fs;
@@ -191,23 +296,33 @@ lfs_newbuf(fs, daddr, size)
        BUF *bp;
        VNODE *devvp;
 
        BUF *bp;
        VNODE *devvp;
 
-printf("lfs_newbuf\n");
        bp = getnewbuf();
        bremhash(bp);
 
        /*
         * XXX
         * Need a devvp, but this isn't a particularly clean way to get one.
        bp = getnewbuf();
        bremhash(bp);
 
        /*
         * XXX
         * Need a devvp, but this isn't a particularly clean way to get one.
+        * devvp = VTOI(fs->lfs_ivnode)->i_devvp;
         */
         */
-       devvp = VTOI(fs->lfs_ivnode)->i_devvp;
+#ifdef NOTWORKING
+       devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
        bgetvp(devvp, bp);
        bgetvp(devvp, bp);
+#endif
+       bp->b_vp = fs->lfs_ivnode;
+       bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev;
        bp->b_bcount = 0;
        bp->b_bcount = 0;
-       bp->b_lblkno = daddr;
-       bp->b_blkno = daddr;
+       bp->b_blkno = bp->b_lblkno = daddr;
        bp->b_error = 0;
        bp->b_resid = 0;
        bp->b_error = 0;
        bp->b_resid = 0;
+       bp->b_flags |= B_CALL | B_DELWRI | B_NOCACHE | B_WRITE;
+       bp->b_iodone = lfs_biocallback;
+#ifdef PROBABLYWRONG
        binshash(bp, BUFHASH(devvp, daddr));
        binshash(bp, BUFHASH(devvp, daddr));
+#endif
        allocbuf(bp, size);
        allocbuf(bp, size);
+#ifdef PROBABLYWRONG
+       reassignbuf(bp, devvp);
+#endif
        return (bp);
 }
 
        return (bp);
 }
 
@@ -225,17 +340,20 @@ lfs_newseg(fs)
 printf("lfs_newseg\n");
        /* Get buffer space to write out a segment */
        sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK);
 printf("lfs_newseg\n");
        /* Get buffer space to write out a segment */
        sp = malloc(sizeof(SEGMENT), M_SEGMENT, M_WAITOK);
+       sp->ibp = NULL;
+       sp->sbp = NULL;
        sp->cbpp = sp->bpp =
            malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK);
        sp->nextp = NULL;
        sp->sum_bytes_left = LFS_SUMMARY_SIZE;
        sp->seg_bytes_left = (fs->lfs_segmask + 1) - LFS_SUMMARY_SIZE;
        sp->saddr = fs->lfs_nextseg;
        sp->cbpp = sp->bpp =
            malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK);
        sp->nextp = NULL;
        sp->sum_bytes_left = LFS_SUMMARY_SIZE;
        sp->seg_bytes_left = (fs->lfs_segmask + 1) - LFS_SUMMARY_SIZE;
        sp->saddr = fs->lfs_nextseg;
+printf("lfs_newseg: About to write segment %lx\n", sp->saddr);
        sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE;
        sp->ninodes = 0;
        sp->sum_num = -1;
        sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE;
        sp->ninodes = 0;
        sp->sum_num = -1;
-       sp->seg_number = (sp->saddr - fs->lfs_sboffs[0]) /
-           fsbtodb(fs, fs->lfs_ssize);
+       sp->seg_number =
+           (sp->saddr - fs->lfs_sboffs[0]) / fsbtodb(fs, fs->lfs_ssize);
 
        /* initialize segment summary info */
        lfs_newsum(fs, sp);
 
        /* initialize segment summary info */
        lfs_newsum(fs, sp);
@@ -245,7 +363,10 @@ printf("lfs_newseg\n");
                /* This is a segment containing a super block */
                FINFO *fip;
                daddr_t lbn, *lbnp;
                /* This is a segment containing a super block */
                FINFO *fip;
                daddr_t lbn, *lbnp;
+               SEGSUM *ssp;
 
 
+               ssp = (SEGSUM *)sp->segsum;
+               ssp->ss_nfinfo++;
                fip = sp->fip;
                fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift;
                fip->fi_version = 1;
                fip = sp->fip;
                fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift;
                fip->fi_version = 1;
@@ -269,25 +390,42 @@ lfs_newsum(fs, sp)
        SEGMENT *sp;
 {
        SEGSUM *ssp;
        SEGMENT *sp;
 {
        SEGSUM *ssp;
-       void *sum;
+       int npages, nseg_pages, sums_per_blk;
 
 printf("lfs_newsum\n");
 
 printf("lfs_newsum\n");
-       sp->sum_num++;
-       if (sp->sum_num == 0) {
-               sum = malloc(fs->lfs_bsize, M_SEGMENT, M_WAITOK);
-               sp->segsum = sum + fs->lfs_bsize - LFS_SUMMARY_SIZE;
-               ssp = sp->segsum;
-               ssp->ss_next = fs->lfs_nextseg = lfs_nextseg(fs);
-               ssp->ss_prev = fs->lfs_lastseg;
+       lfs_endsum(fs, sp, 1);
+       ++sp->sum_num;
+       if (sp->sbp == NULL) {
+               /* Allocate a new buffer. */
+               if (sp->seg_bytes_left < fs->lfs_bsize) {
+                       lfs_writeseg(fs, sp);
+                       sp = lfs_newseg(fs);
+               }
+               sums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+               nseg_pages = 1 + sp->sum_num / sums_per_blk;
+               npages = nseg_pages + (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
+               sp->sum_addr = fs->lfs_sboffs[0] + 
+                   (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize)
+                   - fsbtodb(fs, npages);
+               sp->sbp = lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize);
+               sp->bpp[fs->lfs_ssize - npages] = sp->sbp;
+printf("Inserting summary block, address %x at index %d\n",
+sp->sbp->b_lblkno, fs->lfs_ssize - npages);
+               sp->seg_bytes_left -= fs->lfs_bsize;
+               sp->segsum = sp->sbp->b_un.b_addr + fs->lfs_bsize - LFS_SUMMARY_SIZE;
+               sp->sum_addr += (fs->lfs_bsize - LFS_SUMMARY_SIZE) / DEV_BSIZE;
        } else {
        } else {
-               lfs_endsum(fs, sp, 1);
-               ssp = sp->segsum;
-               ssp->ss_next = ssp->ss_next;
-               ssp->ss_prev = ssp->ss_prev;
+               sp->segsum -= LFS_SUMMARY_SIZE;
+               sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE;
        }
 
        }
 
+       ssp = sp->segsum;
+       ssp->ss_next = fs->lfs_nextseg = lfs_nextseg(fs);
+       ssp->ss_prev = fs->lfs_lastseg;
+
        /* Initialize segment summary info. */
        sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM));
        /* Initialize segment summary info. */
        sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM));
+       sp->fip->fi_nblocks = 0;
        ssp->ss_nextsum = (daddr_t)-1;
        ssp->ss_create = time.tv_sec;
 
        ssp->ss_nextsum = (daddr_t)-1;
        ssp->ss_create = time.tv_sec;
 
@@ -305,13 +443,11 @@ lfs_nextseg(fs)
        int segnum, sn;
        SEGUSE *sup;
 
        int segnum, sn;
        SEGUSE *sup;
 
-printf("lfs_nextseg\n");
        segnum = satosn(fs, fs->lfs_nextseg);
        segnum = satosn(fs, fs->lfs_nextseg);
-       for (sn = seginc(fs, sn); sn != segnum; sn = seginc(fs, sn)) {
-               sup = &fs->lfs_segtab[sn];
-               if (!(sup->su_flags & SEGUSE_DIRTY))
+       for (sn = seginc(fs, segnum); sn != segnum; sn = seginc(fs, sn))
+               if (!(fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY))
                        break;
                        break;
-       }
+
        if (sn == segnum)
                panic("lfs_nextseg: file system full");         /* XXX */
        return(sntosa(fs, sn));
        if (sn == segnum)
                panic("lfs_nextseg: file system full");         /* XXX */
        return(sntosa(fs, sn));
@@ -321,27 +457,42 @@ printf("lfs_nextseg\n");
  * Update the metadata that points to the blocks listed in the FIP
  * array.
  */
  * Update the metadata that points to the blocks listed in the FIP
  * array.
  */
-static
-lfs_updatemeta(fs, ip, fip, bpp)
+static void
+lfs_updatemeta(fs, sp, ip, lbp, bpp, nblocks)
        LFS *fs;
        LFS *fs;
+       SEGMENT *sp;
        INODE *ip;
        INODE *ip;
-       FINFO *fip;
+       daddr_t *lbp;
        BUF **bpp;
        BUF **bpp;
+       int nblocks;
 {
        SEGUSE *segup;
 {
        SEGUSE *segup;
-       BUF **lbpp, *bp;
+       BUF **lbpp, *bp, *mbp;
        daddr_t da, iblkno;
        daddr_t da, iblkno;
-       int error, i, oldsegnum;
-       long lbn, *lbp;
+       int db_per_fsb, error, i, oldsegnum;
+       long lbn;
 
 
-printf("lfs_updatemeta\n");    
-       for (lbpp= bpp, lbp = fip->fi_blocks, i = 0; 
-           i < fip->fi_nblocks; i++, lbp++, bp++) {
-               lbn = *lbp;
+printf("lfs_updatemeta of %d blocks\n", nblocks);      
+       if ((nblocks == 0) && (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0)
+               return;
+
+       /* First sort the blocks and add disk addresses */
+       shellsort(bpp, lbp, nblocks);
+
+       db_per_fsb = 1 << fs->lfs_fsbtodb;
+       for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) {
+               (*lbpp)->b_blkno = sp->saddr;
+               sp->saddr += db_per_fsb;
+       }
+
+       for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) {
+               lbn = lbp[i];
+printf("lfs_updatemeta: block %d\n", lbn);
                if (error = lfs_bmap(ip, lbn, &da))
                if (error = lfs_bmap(ip, lbn, &da))
-                       return(error);
+                   panic("lfs_updatemeta: lfs_bmap returned error");
 
                if (da) {
 
                if (da) {
+                       /* Update segment usage information */
                        oldsegnum = (da - fs->lfs_sboffs[0]) /
                            fsbtodb(fs, fs->lfs_ssize);
                        segup = fs->lfs_segtab+oldsegnum;
                        oldsegnum = (da - fs->lfs_sboffs[0]) /
                            fsbtodb(fs, fs->lfs_ssize);
                        segup = fs->lfs_segtab+oldsegnum;
@@ -351,136 +502,222 @@ printf("lfs_updatemeta\n");
                                        "in segment", oldsegnum);
                }
 
                                        "in segment", oldsegnum);
                }
 
-               /* Now change whoever points to lbn */
-               if (lbn < NDADDR)
+               /*
+                * Now change whoever points to lbn.  We could start with the
+                * smallest (most negative) block number in these if clauses,
+                * but we assume that indirect blocks are least common, and
+                * handle them separately.
+                */
+               bp = NULL;
+               if (lbn < 0) {
+                       if (lbn < -NIADDR) {
+printf("lfs_updatemeta: changing indirect block %d\n", D_INDIR);
+                               if (error = bread(ITOV(ip), D_INDIR, 
+                                   fs->lfs_bsize, NOCRED, &bp))
+                                   panic("lfs_updatemeta: error on bread");
+
+                               bp->b_un.b_daddr[-lbn % NINDIR(fs)] = 
+                                   (*lbpp)->b_blkno;
+                       } else
+                               ip->i_din.di_ib[-lbn-1] = (*lbpp)->b_blkno;
+                       
+               } else if (lbn < NDADDR) 
                        ip->i_din.di_db[lbn] = (*lbpp)->b_blkno;
                else if ((lbn -= NDADDR) < NINDIR(fs)) {
 printf("lfs_updatemeta: changing indirect block %d\n", S_INDIR);
                        ip->i_din.di_db[lbn] = (*lbpp)->b_blkno;
                else if ((lbn -= NDADDR) < NINDIR(fs)) {
 printf("lfs_updatemeta: changing indirect block %d\n", S_INDIR);
-                       error = bread(ITOV(ip), S_INDIR, fs->lfs_bsize, 
-                           NOCRED, &bp);
-                       if (error)
-                               return(error);
+                       if (error = bread(ITOV(ip), S_INDIR, fs->lfs_bsize, 
+                           NOCRED, &bp))
+                           panic("lfs_updatemeta: bread returned error");
+
                        bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno;
                        bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno;
-                       brelse(bp);
                } else if ( (lbn = (lbn - NINDIR(fs)) / NINDIR(fs)) < 
                            NINDIR(fs)) {
 
                        iblkno = - (lbn + NIADDR + 1);
 printf("lfs_updatemeta: changing indirect block %d\n", iblkno);
                } else if ( (lbn = (lbn - NINDIR(fs)) / NINDIR(fs)) < 
                            NINDIR(fs)) {
 
                        iblkno = - (lbn + NIADDR + 1);
 printf("lfs_updatemeta: changing indirect block %d\n", iblkno);
-                       error = bread(ITOV(ip), iblkno, fs->lfs_bsize, NOCRED
-                           &bp);
-                       if (error)
-                               return(error);
+                       if (error = bread(ITOV(ip), iblkno, fs->lfs_bsize
+                           NOCRED, &bp))
+                           panic("lfs_updatemeta: bread returned error");
+
                        bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno;
                }
                else
                        bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno;
                }
                else
-                       return(EFBIG);
+                       panic("lfs_updatemeta: logical block number too large");
+               if (bp)
+                       lfs_bwrite(bp);
        }
        }
-       return(0);
+}
+
+static void
+lfs_writeckp(fs, sp)
+       LFS *fs;
+       SEGMENT *sp;
+{
+       BUF *bp;
+       FINFO *fip;
+       INODE *ip;
+       SEGUSE *sup;
+       daddr_t *lbp;
+       int bytes_needed, i;
+       void *xp;
+
+printf("lfs_writeckp\n");
+       /*
+        * This will write the dirty ifile blocks, but not the segusage
+        * table nor the ifile inode.
+        */
+       sp = lfs_writefile(sp, fs, fs->lfs_ivnode, 1);
+
+       /*
+        * Make sure that the segment usage table and the ifile inode will
+        * fit in this segment.  If they won't, put them in the next segment
+        */
+       bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift;
+       if (sp->ninodes % INOPB(fs) == 0)
+               bytes_needed += fs->lfs_bsize;
+
+       if (sp->seg_bytes_left < bytes_needed) {
+               lfs_writeseg(fs, sp);
+               sp = lfs_newseg(fs);
+       } else if (sp->sum_bytes_left < (fs->lfs_segtabsz * sizeof(daddr_t)))
+               lfs_newsum(fs, sp);
+
+#ifdef DEBUG
+       if (sp->seg_bytes_left < bytes_needed)
+               panic("lfs_writeckp: unable to write checkpoint");
+#endif
+
+       /*
+        * Now, update the segment usage information and the ifile inode and
+        * and write it out
+        */
+
+       sup = fs->lfs_segtab + sp->seg_number;
+       sup->su_nbytes = (fs->lfs_segmask + 1) - sp->seg_bytes_left + 
+           bytes_needed;
+       sup->su_lastmod = time.tv_sec;
+       sup->su_flags = SEGUSE_DIRTY;
+
+       /* Get buffers for the segusage table and write it out */
+       ip = VTOI(fs->lfs_ivnode);
+       fip = sp->fip;
+       lbp = &fip->fi_blocks[fip->fi_nblocks];
+       for (xp = fs->lfs_segtab, i = 0; i < fs->lfs_segtabsz; 
+           i++, xp += fs->lfs_bsize, lbp++) {
+               bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize);
+               *sp->cbpp++ = bp;
+               bcopy(xp, bp->b_un.b_words, fs->lfs_bsize);
+               ip->i_din.di_db[i] = sp->saddr;
+               sp->saddr += (1 << fs->lfs_fsbtodb);
+               *lbp = i;
+               fip->fi_nblocks++;
+       }
+       sp = lfs_writeinode(fs, sp, fs->lfs_ivnode);
+       lfs_writeseg(fs, sp);
+       lfs_writesuper(fs, sp);
 }
 
 /*
 }
 
 /*
- * Returns 0 if the entire file fit into the current segment and
- * summary region, 1 if not.
  * XXX -- I think we need to figure out what to do if we write
  * the segment and find more dirty blocks when we're done.
  */
 static SEGMENT *
  * XXX -- I think we need to figure out what to do if we write
  * the segment and find more dirty blocks when we're done.
  */
 static SEGMENT *
-lfs_writefile(sp, fs, vp)
+lfs_writefile(sp, fs, vp, do_ckp)
        SEGMENT *sp;
        LFS *fs;
        VNODE *vp;
        SEGMENT *sp;
        LFS *fs;
        VNODE *vp;
+       int do_ckp;
 {
 {
-       register BUF *bp;
-       BUF **bpp, *nbp;
        FINFO *fip;
        INODE *ip;
        FINFO *fip;
        INODE *ip;
-       int db_per_fsb, error, i;
-       int ret_val, s;
-       long *lbp;
 
        /* initialize the FINFO structure */
        ip = VTOI(vp);
 printf("lfs_writefile: node %d\n", ip->i_number);
 loop:
 
        /* initialize the FINFO structure */
        ip = VTOI(vp);
 printf("lfs_writefile: node %d\n", ip->i_number);
 loop:
-       fip = sp->fip;
-       fip->fi_nblocks = 0;
-       fip->fi_ino = ip->i_number;
-       fip->fi_version = lfs_getversion(fs, ip->i_number);
-       lbp = fip->fi_blocks;
-       
-       bpp = sp->cbpp;
-       s = splbio();
-       for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
-               nbp = bp->b_blockf;
-printf("lfs_writefile: disk block num %d flags %x\n", bp->b_blkno, bp->b_flags);
-               if ((bp->b_flags & B_BUSY))
-                       continue;
-               if ((bp->b_flags & B_DELWRI) == 0)
-                       panic("lfs_write: not dirty");
-               bremfree(bp);
-               bp->b_flags |= (B_BUSY | B_CALL);
-               bp->b_iodone = lfs_biocallback;
-
-               /* UFS does the bawrites and bwrites here; we don't */
-               *lbp++ = bp->b_lblkno;          /* UPDATE META HERE */
-               *sp->cbpp++ = bp;
-               fip->fi_nblocks++;
-               sp->sum_bytes_left -= sizeof(daddr_t);
-               sp->seg_bytes_left -= bp->b_bufsize;
-               if (sp->sum_bytes_left < sizeof(daddr_t) || 
-                   sp->seg_bytes_left < fs->lfs_bsize) {
-                       /*
-                        * We are about to allocate a new summary block
-                        * and possibly a new segment.  So, we need to
-                        * sort the blocks we've done so far, and assign
-                        * the disk addresses, so we can start a new block
-                        * correctly.  We may be doing I/O so we need to
-                        * release the s lock before doing anything.
-                        */
-                       splx(s);
-                       if (error = lfs_updatemeta(fs, ip, fip, bpp))
-                               panic("lfs_writefile: error from lfs_updatemeta\n");
+       sp->fip->fi_nblocks = 0;
+       sp->fip->fi_ino = ip->i_number;
+       if (ip->i_number != LFS_IFILE_INUM)
+               sp->fip->fi_version = lfs_getversion(fs, ip->i_number);
+       else
+               sp->fip->fi_version = 1;
+
+       sp = lfs_gather(fs, sp, vp, match_data);
+       if (do_ckp) {
+               sp = lfs_gather(fs, sp, vp, match_indir);
+               sp = lfs_gather(fs, sp, vp, match_dindir);
+       }
 
 
-                       /* Put this file in the segment summary */
+(void)printf("lfs_writefile: adding %d blocks to segment\n",
+sp->fip->fi_nblocks);
+       /* 
+        * Update the inode for this file and reflect new inode
+        * address in the ifile.  If this is the ifile, don't update
+        * the inode, because we're checkpointing and will update the
+        * inode with the segment usage information (so we musn't
+        * bump the finfo pointer either).
+        */
+       if (ip->i_number != LFS_IFILE_INUM) {
+               sp = lfs_writeinode(fs, sp, vp);
+               fip = sp->fip;
+               if (fip->fi_nblocks) {
                        ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
                        ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
-
-                       if (sp->seg_bytes_left < fs->lfs_bsize) {
-                               lfs_writeseg(fs, sp);
-                               sp = lfs_newseg(fs);
-                       } else if (sp->sum_bytes_left < sizeof(daddr_t))
-                               lfs_newsum(fs, sp);
-                       fip = sp->fip;
-                       s = splbio();
+                       sp->fip = (FINFO *)((u_long)fip + sizeof(FINFO) + 
+                           sizeof(u_long) * fip->fi_nblocks - 1);
                }
                }
-
-       }
-       splx(s);
-       db_per_fsb = 1 << fs->lfs_fsbtodb;
-       shellsort(bpp, (u_long *)fip->fi_blocks, fip->fi_nblocks);
-       for (bp = *bpp, i = 0; i < fip->fi_nblocks; i++, bp++) {
-               bp->b_blkno = sp->saddr;
-               sp->saddr += db_per_fsb;
-               /* 
-                * Update the meta data now for this file.  If we've filled
-                * a segment, then we'll have to wait until the next segment
-                * to write out the updated metadata.
-                */
-               lfs_writemeta();
-       }
-(void)printf("lfs_writefile: adding %d blocks to segment\n", fip->fi_nblocks);
-       if (fip->fi_nblocks) {
-               ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
-               sp->fip = (FINFO *)((u_long)fip + sizeof(FINFO) + 
-                   sizeof(u_long) * (fip->fi_nblocks - 1));
        }
        return(sp);
 }
 
        }
        return(sp);
 }
 
-static void
-lfs_writemeta()
+static SEGMENT *
+lfs_writeinode(fs, sp, vp)
+       LFS *fs;
+       SEGMENT *sp;
+       VNODE *vp;
 {
 {
-       printf("lfs_writemeta (STUB)\n");
+       BUF *bp;
+       INODE *ip;
+       SEGSUM *ssp;
+       daddr_t iaddr, next_addr;
+       int npages, nseg_pages, sums_per_blk;
+       struct dinode *dip;
+
+printf("lfs_writeinode\n");
+       sums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+       if (sp->ibp == NULL) {
+               /* Allocate a new buffer. */
+               if (sp->seg_bytes_left < fs->lfs_bsize) {
+                       lfs_writeseg(fs, sp);
+                       sp = lfs_newseg(fs);
+               }
+               nseg_pages = (sp->sum_num + sums_per_blk) / sums_per_blk;
+               npages = nseg_pages + (sp->ninodes + INOPB(fs)) / INOPB(fs);
+               next_addr = fs->lfs_sboffs[0] + 
+                   (sp->seg_number + 1) * fsbtodb(fs, fs->lfs_ssize)
+                   - fsbtodb(fs, npages);
+               sp->ibp = lfs_newbuf(fs, next_addr, fs->lfs_bsize);
+               sp->ibp->b_flags |= B_BUSY;
+               sp->bpp[fs->lfs_ssize - npages] = sp->ibp;
+               sp->seg_bytes_left -= fs->lfs_bsize;
+printf("alloc inode block @ daddr %x, bp = %x inserted at %d\n", 
+next_addr, sp->ibp, fs->lfs_ssize - npages);
+       }
+       ip = VTOI(vp);
+       bp = sp->ibp;
+       dip = bp->b_un.b_dino + (sp->ninodes % INOPB(fs));
+       bcopy(&ip->i_din, dip, sizeof(struct dinode));
+       iaddr = bp->b_blkno;
+       ++sp->ninodes;
+       ssp = sp->segsum;
+       ++ssp->ss_ninos;
+       if (sp->ninodes % INOPB(fs) == 0)
+               sp->ibp = NULL;
+       if (ip->i_number == LFS_IFILE_INUM)
+               fs->lfs_idaddr = iaddr;
+       else
+               lfs_iset(ip, iaddr, ip->i_atime);       /* Update ifile */
+       ip->i_flags &= ~(IMOD|IACC|IUPD|ICHG);          /* make inode clean */
+       return(sp);
 }
 
 static void
 }
 
 static void
@@ -488,67 +725,128 @@ lfs_writeseg(fs, sp)
        LFS *fs;
        SEGMENT *sp;
 {
        LFS *fs;
        SEGMENT *sp;
 {
-       BUF **bpp, *bp;
+       BUF **bpp;
        SEGSUM *ssp;
        SEGUSE *sup;
        VNODE *devvp;
        int nblocks, nbuffers, ninode_blocks, nsegsums, nsum_pb;
        int i, metaoff, nmeta;
        SEGSUM *ssp;
        SEGUSE *sup;
        VNODE *devvp;
        int nblocks, nbuffers, ninode_blocks, nsegsums, nsum_pb;
        int i, metaoff, nmeta;
+struct buf **xbp; int xi;
 
 printf("lfs_writeseg\n");
 
 printf("lfs_writeseg\n");
-       ssp = sp->segsum;
-       nsum_pb = fs->lfs_bsize / LFS_SUMMARY_SIZE;
-       /*
-        * This is a hack because we're currently allocating summary segments
-        * in full blocks.  It will go away when we do fragments, when we'll
-        * allocate fragment sized summary blocks.
-        */
-       do {
-               sp->sum_num++;
-               lfs_endsum(fs, sp, 0);
-       } while (sp->sum_num % nsum_pb);
-       nbuffers = sp->cbpp - sp->bpp;
-       nsegsums = (sp->sum_num + nsum_pb - 1) / nsum_pb;
-       ninode_blocks = (sp->ninodes + INOPB(fs) - 1)/INOPB(fs);
-
-       /* Do checksum for last segment summary */
-       ssp->ss_cksum = cksum(&ssp->ss_cksum, 
-                   LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
+       fs->lfs_lastseg = sntosa(fs, sp->seg_number);
+       lfs_endsum(fs, sp, 0);
 
 
+#ifdef HELLNO
        /* Finish off any inodes */
        /* Finish off any inodes */
+       if (sp->ibp)
+               brelse(sp->ibp);
+#endif
 
        /*
         * Copy inode and summary block buffer pointers down so they are
 
        /*
         * Copy inode and summary block buffer pointers down so they are
-        * contiguous with the page buffer pointers
+        * contiguous with the page buffer pointers.
         */
         */
-       nmeta = 1 + ninode_blocks + nsegsums;
+       ssp = sp->segsum;
+       nsum_pb = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+       nbuffers = sp->cbpp - sp->bpp;
+       nsegsums = 1 + sp->sum_num / nsum_pb;
+       ninode_blocks = (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
+       nmeta = ninode_blocks + nsegsums;
        metaoff = fs->lfs_ssize - nmeta;
        metaoff = fs->lfs_ssize - nmeta;
+       nblocks = nbuffers + nmeta;
        if (sp->bpp + metaoff != sp->cbpp)
        if (sp->bpp + metaoff != sp->cbpp)
-               bcopy(sp->bpp+metaoff, sp->cbpp, sizeof(BUF *)  * nmeta);
+               bcopy(sp->bpp + metaoff, sp->cbpp, sizeof(BUF *) * nmeta);
+       sp->cbpp += nmeta;
 
 
-       nblocks = nbuffers + ninode_blocks + nsegsums;
-       
        sup = fs->lfs_segtab + sp->seg_number;
        sup->su_nbytes = nblocks << fs->lfs_bshift;
        sup->su_lastmod = time.tv_sec;
        sup->su_flags = SEGUSE_DIRTY;
 
        /*
        sup = fs->lfs_segtab + sp->seg_number;
        sup->su_nbytes = nblocks << fs->lfs_bshift;
        sup->su_lastmod = time.tv_sec;
        sup->su_flags = SEGUSE_DIRTY;
 
        /*
-        * Since we need to guarantee that our last buffer gets written last,
+        * Since we need to guarantee that the summary block gets written last,
         * we issue the writes in two sets.  The first n-1 buffers first, and
         * then, after they've completed, the last 1 buffer.  Only when that
         * we issue the writes in two sets.  The first n-1 buffers first, and
         * then, after they've completed, the last 1 buffer.  Only when that
-        * final write completes is the segment actually written.
+        * final write completes is the segment valid.
         */
        devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
         */
        devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
-/* MIS -- THIS COULD BE BAD IF WE GOT INTERRUPTED IN THE MIDDLE OF THIS */
-       fs->lfs_iocount += nblocks - 1;
+       /*
+        * Since no writes are yet scheduled, no need to block here; if we
+        * scheduled the writes at multiple points, we'd need an splbio()
+        * here.
+        */
+       fs->lfs_iocount = nblocks - 1;
        sp->nextp = fs->lfs_seglist;
        fs->lfs_seglist = sp;
        sp->nextp = fs->lfs_seglist;
        fs->lfs_seglist = sp;
-       for (bpp = sp->bpp, i = 0; i < (nblocks - 1); i++) {
-               bp = *bpp;
-printf("lfs_writeseg: buffer: ino %d lbn %d flags %lx\n", VTOI(bp->b_vp)->i_number, bp->b_lblkno, bp->b_flags);
-               (*(devvp->v_op->vop_strategy))(*bpp++);
-       }
+
+       for (bpp = sp->bpp, i = 0; i < (nblocks - 1); i++, ++bpp)
+               /* (*(devvp->v_op->vop_strategy)) */ sdstrategy(*bpp);
+}
+
+static void
+lfs_writesuper(fs, sp)
+       LFS *fs;
+       SEGMENT *sp;
+{
+       BUF *bp;
+       VNODE *devvp;
+
+printf("lfs_writesuper\n");
+       /* Wait for segment write to complete */
+       /* XXX probably should do this biowait(*(sp->cbpp - 1)); */
+
+       /* Get a buffer for the super block */
+       fs->lfs_cksum = cksum(fs, sizeof(LFS) - sizeof(fs->lfs_cksum));
+       bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD);
+       bp->b_flags &= ~B_CALL;
+       bp->b_vp = NULL;
+       bp->b_iodone = NULL;
+       bcopy(fs, bp->b_un.b_lfs, sizeof(LFS));
+
+       /* Write the first superblock; wait. */
+       devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
+#ifdef MOVETONEWBUF
+       bp->b_dev = devvp->v_rdev;
+#endif
+       (*devvp->v_op->vop_strategy)(bp);
+       biowait(bp);
+       
+       /* Now, write the second one for which we don't have to wait */
+       bp->b_flags &= ~B_DONE;
+       bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1];
+       (*devvp->v_op->vop_strategy)(bp);
+       brelse(bp);
+}
+
+/* Block match routines used when traversing the dirty block chain. */
+match_data(bp)
+       BUF *bp;
+{
+       return(bp->b_lblkno >= 0);
+}
+
+
+match_dindir(bp)
+       BUF *bp;
+{
+       return(bp->b_lblkno == D_INDIR);
+}
+
+/*
+ * These are single indirect blocks.  There are three types:
+ *     the one in the inode (address S_INDIR = -1).
+ *     the ones that hang off of D_INDIR the double indirect in the inode.
+ *             these all have addresses in the range -2NINDIR to -(3NINDIR-1)
+ *     the ones that hang off of double indirect that hang off of the
+ *             triple indirect.  These all have addresses < -(NINDIR^2).
+ * Since we currently don't support, triple indirect blocks, this gets simpler.
+ * We just need to look for block numbers less than -NIADDR.
+ */
+match_indir(bp)
+       BUF *bp;
+{
+       return(bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR);
 }
 
 /*
 }
 
 /*
@@ -567,7 +865,7 @@ printf("lfs_writeseg: buffer: ino %d lbn %d flags %lx\n", VTOI(bp->b_vp)->i_numb
 static void
 shellsort(bp_array, lb_array, nmemb)
        BUF **bp_array;
 static void
 shellsort(bp_array, lb_array, nmemb)
        BUF **bp_array;
-       u_long *lb_array;
+       daddr_t *lb_array;
        register int nmemb;
 {
        static int __rsshell_increments[] = { 4, 1, 0 };
        register int nmemb;
 {
        static int __rsshell_increments[] = { 4, 1, 0 };
@@ -589,3 +887,4 @@ shellsort(bp_array, lb_array, nmemb)
                                } else
                                        break;
 }
                                } else
                                        break;
 }
+#endif /* LOGFS */