checkpoint after Margo's changes to make sync work
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Thu, 10 Oct 1991 03:19:11 +0000 (19:19 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Thu, 10 Oct 1991 03:19:11 +0000 (19:19 -0800)
SCCS-vsn: sys/ufs/lfs/lfs_segment.c 5.4

usr/src/sys/ufs/lfs/lfs_segment.c

index 7e26658..a74be7a 100644 (file)
@@ -4,7 +4,7 @@
  *
  * %sccs.include.redist.c%
  *
  *
  * %sccs.include.redist.c%
  *
- *     @(#)lfs_segment.c       5.3 (Berkeley) %G%
+ *     @(#)lfs_segment.c       5.4 (Berkeley) %G%
  */
 
 #ifdef LOGFS
  */
 
 #ifdef LOGFS
@@ -47,19 +47,20 @@ 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 *));
                    __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 SEGMENT *lfs_newsum __P((LFS *, SEGMENT *));
 static daddr_t  lfs_nextseg __P((LFS *));
 static daddr_t  lfs_nextseg __P((LFS *));
-static void     lfs_updatemeta __P((LFS *, SEGMENT *, INODE *, daddr_t *, 
+static void     lfs_updatemeta __P((LFS *, SEGMENT *, INODE *, daddr_t *,
                     BUF **, int));
 static SEGMENT *lfs_writeckp __P((LFS *, SEGMENT *));
                     BUF **, int));
 static SEGMENT *lfs_writeckp __P((LFS *, SEGMENT *));
-static SEGMENT *lfs_writefile __P((SEGMENT *, LFS *, VNODE *, int));
-static SEGMENT *lfs_writeinode __P((LFS *, SEGMENT *, VNODE *));
+static SEGMENT *lfs_writefile __P((LFS *, SEGMENT *, VNODE *, int));
+static SEGMENT *lfs_writeinode __P((LFS *, SEGMENT *, INODE *));
 static void     lfs_writeseg __P((LFS *, SEGMENT *));
 static void     lfs_writesum __P((LFS *));
 static void     lfs_writeseg __P((LFS *, SEGMENT *));
 static void     lfs_writesum __P((LFS *));
-static void     lfs_writesuper __P((LFS *, SEGMENT *));
+static void     lfs_writesuper __P((LFS *));
 static int      match_data __P((BUF *));
 static int      match_dindir __P((BUF *));
 static int      match_indir __P((BUF *));
 static int      match_data __P((BUF *));
 static int      match_dindir __P((BUF *));
 static int      match_indir __P((BUF *));
+static daddr_t  next __P((LFS *, SEGMENT *, int *));
 static void     shellsort __P((BUF **, daddr_t *, register int));
 
 /*
 static void     shellsort __P((BUF **, daddr_t *, register int));
 
 /*
@@ -71,7 +72,6 @@ lfs_segwrite(mp, do_ckp)
        MOUNT *mp;
        int do_ckp;                     /* do a checkpoint too */
 {
        MOUNT *mp;
        int do_ckp;                     /* do a checkpoint too */
 {
-       FINFO *fip;                     /* current file info structure */
        INODE *ip;
        LFS *fs;
        VNODE *vp;
        INODE *ip;
        LFS *fs;
        VNODE *vp;
@@ -79,6 +79,12 @@ lfs_segwrite(mp, do_ckp)
        int s;
 
        fs = VFSTOUFS(mp)->um_lfs;
        int s;
 
        fs = VFSTOUFS(mp)->um_lfs;
+
+#ifdef DIAGNOSTIC
+       if (fs->lfs_seglist != NULL)
+               panic("lfs_segwrite: seglist not NULL");
+#endif
+
        /*
         * LFS requires that the summary blocks be written after the rest of
         * the segment, and that the super blocks (on checkpoint) be written
        /*
         * LFS requires that the summary blocks be written after the rest of
         * the segment, and that the super blocks (on checkpoint) be written
@@ -93,7 +99,7 @@ lfs_segwrite(mp, do_ckp)
        s = splbio();
        fs->lfs_iocount = 1;
        splx(s);
        s = splbio();
        fs->lfs_iocount = 1;
        splx(s);
-       
+
        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) {
@@ -108,36 +114,35 @@ loop:
                ip = VTOI(vp);
                if (ip->i_number == LFS_IFILE_INUM)
                        continue;
                ip = VTOI(vp);
                if (ip->i_number == LFS_IFILE_INUM)
                        continue;
-               if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
+               if ((ip->i_flag & (IMOD | IACC | IUPD | ICHG)) == 0 &&
                    vp->v_dirtyblkhd == NULL)
                        continue;
                if (vget(vp))
                        goto loop;
                    vp->v_dirtyblkhd == NULL)
                        continue;
                if (vget(vp))
                        goto loop;
-               sp = lfs_writefile(sp, fs, vp, do_ckp);
+               sp = lfs_writefile(fs, sp, vp, do_ckp);
                vput(vp);
        }
                vput(vp);
        }
-
        if (do_ckp)
                sp = lfs_writeckp(fs, sp);
        if (do_ckp)
                sp = lfs_writeckp(fs, sp);
-       else
-               lfs_writeseg(fs, sp);
+       lfs_writeseg(fs, sp);
+
        s = splbio();
        if (--fs->lfs_iocount)
                sleep(&fs->lfs_iocount, PRIBIO + 1);
        splx(s);
        lfs_writesum(fs);
        if (do_ckp)
        s = splbio();
        if (--fs->lfs_iocount)
                sleep(&fs->lfs_iocount, PRIBIO + 1);
        splx(s);
        lfs_writesum(fs);
        if (do_ckp)
-               lfs_writesuper(fs, sp);
+               lfs_writesuper(fs);
+printf("After writesuper returning\n");
+
        return (0);
 }
 
        return (0);
 }
 
-static int
+static int                                     /* XXX should be void */
 lfs_biocallback(bp)
        BUF *bp;
 {
        LFS *fs;
 lfs_biocallback(bp)
        BUF *bp;
 {
        LFS *fs;
-       SEGMENT *sp, *next_sp;
-       VNODE *devvp;
 
        /*
         * XXX
 
        /*
         * XXX
@@ -160,54 +165,40 @@ printf("callback: buffer: %x iocount %d\n", bp, fs->lfs_iocount);
                wakeup(&fs->lfs_iocount);
 }
 
                wakeup(&fs->lfs_iocount);
 }
 
+/* Finish up a summary block. */
 static void
 lfs_endsum(fs, sp, calc_next)
        LFS *fs;
        SEGMENT *sp;
 static void
 lfs_endsum(fs, sp, calc_next)
        LFS *fs;
        SEGMENT *sp;
-       int calc_next;          /* If 1 calculate next, else set to -1. */
+       int calc_next;
 {
 {
-       BUF *bp;
        SEGSUM *ssp;
        SEGSUM *ssp;
-       daddr_t next_addr;
-       int npages, nseg_pages, nsums_per_blk;
+       int nsums_per_blk;
 
        if (sp->sbp == NULL)
                return;
 
        ssp = sp->segsum;
 
        if (sp->sbp == NULL)
                return;
 
        ssp = sp->segsum;
-       ssp->ss_nextsum = calc_next ?
-           sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE : (daddr_t)-1;
 
        /*
 
        /*
-        * XXX
-        * I don't understand how sum_num works; the 0 base seems wrong.
+        * Compute the address of the next summary block if calc_next is set,
+        * otherwise end the chain.  If the summary block is full, close it
+        * by setting sp->sbp to NULL, so lfs_newsum will allocate a new one.
+        * Calculate the checksum last.
         */
        nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
         */
        nsums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
-       if ((sp->sum_num % (fs->lfs_bsize / LFS_SUMMARY_SIZE)) ==
-           (nsums_per_blk - 1)) {
-               /*
-                * This buffer is now full.  Compute the next address if
-                * appropriate and the checksum, and close the buffer by
-                * setting sp->sbp NULL.
-                */
-               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_cksum = cksum(&ssp->ss_cksum,
-                   LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
+       if (sp->nsums % nsums_per_blk == 0) {
+               ssp->ss_nextsum =
+                   calc_next ? next(fs, sp, NULL) +
+                   (nsums_per_blk - 1) * LFS_SUMMARY_SIZE / DEV_BSIZE :
+                   (daddr_t)-1;
                sp->sbp = NULL;
        } else
                sp->sbp = NULL;
        } else
-               /* Calculate cksum on previous segment summary */
-               ssp->ss_cksum = cksum(&ssp->ss_cksum, 
-                   LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
+               ssp->ss_nextsum = calc_next ?
+                   sp->sum_addr - LFS_SUMMARY_SIZE / DEV_BSIZE : (daddr_t)-1;
+
+       ssp->ss_cksum =
+           cksum(&ssp->ss_cksum, LFS_SUMMARY_SIZE - sizeof(ssp->ss_cksum));
 }
 
 static SEGMENT *
 }
 
 static SEGMENT *
@@ -220,71 +211,82 @@ lfs_gather(fs, sp, vp, match)
        BUF **bpp, *bp, *nbp;
        FINFO *fip;
        INODE *ip;
        BUF **bpp, *bp, *nbp;
        FINFO *fip;
        INODE *ip;
-       int count, s, version;
        daddr_t *lbp, *start_lbp;
        daddr_t *lbp, *start_lbp;
+       u_long version;
+       int s;
 
        ip = VTOI(vp);
        bpp = sp->cbpp;
        fip = sp->fip;
 
        ip = VTOI(vp);
        bpp = sp->cbpp;
        fip = sp->fip;
-       version = fip->fi_version;
        start_lbp = lbp = &fip->fi_blocks[fip->fi_nblocks];
        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;
 
        s = splbio();
        for (bp = vp->v_dirtyblkhd; bp; bp = nbp) {
                nbp = bp->b_blockf;
-               if ((bp->b_flags & B_BUSY))
+               if (bp->b_flags & B_BUSY)
                        continue;
                        continue;
+#ifdef DIAGNOSTIC
                if ((bp->b_flags & B_DELWRI) == 0)
                if ((bp->b_flags & B_DELWRI) == 0)
-                       panic("lfs_write: not dirty");
+                       panic("lfs_gather: not dirty");
+#endif
                if (!match(bp))
                        continue;
                if (!match(bp))
                        continue;
+
+               /* Remove the buffer from the free lists, prepare it for I/O. */
                bremfree(bp);
                bp->b_flags |= B_BUSY | B_CALL;
                bp->b_iodone = lfs_biocallback;
                bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev;
 
                bremfree(bp);
                bp->b_flags |= B_BUSY | B_CALL;
                bp->b_iodone = lfs_biocallback;
                bp->b_dev = VTOI(fs->lfs_ivnode)->i_dev;
 
-               *lbp++ = bp->b_lblkno;
+               /* Insert into the buffer list, update the FINFO block. */
                *sp->cbpp++ = bp;
                *sp->cbpp++ = bp;
-               fip->fi_nblocks++;
+               ++fip->fi_nblocks;
+               *lbp++ = bp->b_lblkno;
+
                sp->sum_bytes_left -= sizeof(daddr_t);
                sp->seg_bytes_left -= bp->b_bufsize;
                sp->sum_bytes_left -= sizeof(daddr_t);
                sp->seg_bytes_left -= bp->b_bufsize;
-               if (sp->sum_bytes_left < sizeof(daddr_t) || 
+
+               /*
+                * Allocate a new summary block (and, possibly, a new segment)
+                * if necessary.  In this case we sort the blocks we've done
+                * so far and assign disk addresses so we can start the new
+                * block correctly.  We may be doing I/O, so we need to release
+                * the splbio() before anything else.
+                */
+               if (sp->sum_bytes_left < sizeof(daddr_t) ||
                    sp->seg_bytes_left < fs->lfs_bsize) {
                    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);
                        splx(s);
-                       lfs_updatemeta(fs, sp, ip, start_lbp, bpp,
-                           lbp - start_lbp);
+                       lfs_updatemeta(fs,
+                           sp, ip, start_lbp, bpp, lbp - start_lbp);
 
 
-                       /* Put this file in the segment summary */
-                       ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
+                       /* Add the current file to the segment summary. */
+                       ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
 
 
+                       version = fip->fi_version;
                        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))
                        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);
+                               sp = lfs_newsum(fs, sp);
+
+                       /* A new FINFO either way. */
                        fip = sp->fip;
                        fip = sp->fip;
-                       fip->fi_ino = ip->i_number;
                        fip->fi_version = version;
                        fip->fi_version = version;
-                       bpp = sp->cbpp;
-                       /* You know that you have a new FINFO either way. */
+                       fip->fi_ino = ip->i_number;
                        start_lbp = lbp = fip->fi_blocks;
                        start_lbp = lbp = fip->fi_blocks;
+
+                       bpp = sp->cbpp;
                        s = splbio();
                }
        }
        splx(s);
        lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp);
                        s = splbio();
                }
        }
        splx(s);
        lfs_updatemeta(fs, sp, ip, start_lbp, bpp, lbp - start_lbp);
-       return(sp);
+       return (sp);
 }
 
 }
 
+/*
+ * Allocate a new buffer header.
+ */
 static BUF *
 lfs_newbuf(fs, daddr, size)
        LFS *fs;
 static BUF *
 lfs_newbuf(fs, daddr, size)
        LFS *fs;
@@ -307,13 +309,18 @@ lfs_newbuf(fs, daddr, size)
        return (bp);
 }
 
        return (bp);
 }
 
-/* Start a new segment. */
+/*
+ * Start a new segment.
+ */
 static SEGMENT *
 lfs_newseg(fs)
        LFS *fs;
 {
 static SEGMENT *
 lfs_newseg(fs)
        LFS *fs;
 {
+       FINFO *fip;
        SEGMENT *sp;
        SEGUSE *sup;
        SEGMENT *sp;
        SEGUSE *sup;
+       SEGSUM *ssp;
+       daddr_t lbn, *lbnp;
 
 printf("lfs_newseg: new segment %x\n", fs->lfs_nextseg);
 
 
 printf("lfs_newseg: new segment %x\n", fs->lfs_nextseg);
 
@@ -322,119 +329,138 @@ printf("lfs_newseg: new segment %x\n", fs->lfs_nextseg);
        sp->cbpp = sp->bpp =
            malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK);
        sp->ibp = sp->sbp = NULL;
        sp->cbpp = sp->bpp =
            malloc(fs->lfs_ssize * sizeof(BUF *), M_SEGMENT, M_WAITOK);
        sp->ibp = sp->sbp = NULL;
-       sp->sum_bytes_left = LFS_SUMMARY_SIZE;
-       sp->seg_bytes_left = (fs->lfs_segmask + 1) - LFS_SUMMARY_SIZE;
+       sp->seg_bytes_left = (fs->lfs_segmask + 1);
        sp->saddr = fs->lfs_nextseg;
        sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE;
        sp->ninodes = 0;
        sp->saddr = fs->lfs_nextseg;
        sp->sum_addr = sp->saddr + sp->seg_bytes_left / DEV_BSIZE;
        sp->ninodes = 0;
-       sp->sum_num = -1;
+       sp->nsums = 0;
        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);
 
-       /* Bump the segment count. */
+       /* Advance to the next segment. */
        fs->lfs_nextseg = lfs_nextseg(fs);
        fs->lfs_nextseg = lfs_nextseg(fs);
-       lfs_newsum(fs, sp);                     /* Init sp->segsum. */
 
 
-       sup = fs->lfs_segtab + sp->seg_number;
+       /* Initialize the summary block. */
+       sp = lfs_newsum(fs, sp);
 
 
+       /*
+        * If su_nbytes non-zero after the segment was cleaned, the segment
+        * contains a super-block.  Add segment summary information to not
+        * allocate over it.
+        */
+       sup = fs->lfs_segtab + sp->seg_number;
        if (sup->su_nbytes != 0) {
        if (sup->su_nbytes != 0) {
-               /* This is a segment containing a super block. */
-               FINFO *fip;
-               daddr_t lbn, *lbnp;
-               SEGSUM *ssp;
-
                ssp = (SEGSUM *)sp->segsum;
                ssp = (SEGSUM *)sp->segsum;
-               ssp->ss_nfinfo++;
+               ++ssp->ss_nfinfo;
                fip = sp->fip;
                fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift;
                fip->fi_version = 1;
                fip->fi_ino = LFS_UNUSED_INUM;
                fip = sp->fip;
                fip->fi_nblocks = LFS_SBPAD >> fs->lfs_bshift;
                fip->fi_version = 1;
                fip->fi_ino = LFS_UNUSED_INUM;
-               sp->saddr += fsbtodb(fs, fip->fi_nblocks);
                lbnp = fip->fi_blocks;
                lbnp = fip->fi_blocks;
-               for (lbn = 0; lbn < fip->fi_nblocks; lbn++)
+               for (lbn = 0; lbn < fip->fi_nblocks; ++lbn)
                        *lbnp++ = lbn;
                        *lbnp++ = lbn;
+               sp->saddr += fsbtodb(fs, fip->fi_nblocks);
                sp->seg_bytes_left -= sup->su_nbytes;
                sp->seg_bytes_left -= sup->su_nbytes;
-               sp->sum_bytes_left -= 
+               sp->sum_bytes_left -=
                    sizeof(FINFO) + (fip->fi_nblocks - 1) * sizeof(daddr_t);
                sp->fip = (FINFO *)lbnp;
        }
                    sizeof(FINFO) + (fip->fi_nblocks - 1) * sizeof(daddr_t);
                sp->fip = (FINFO *)lbnp;
        }
-       return(sp);
+       return (sp);
 }
 
 }
 
-static void
+static SEGMENT *
 lfs_newsum(fs, sp)
        LFS *fs;
        SEGMENT *sp;
 {
        SEGSUM *ssp;
 lfs_newsum(fs, sp)
        LFS *fs;
        SEGMENT *sp;
 {
        SEGSUM *ssp;
-       int npages, nseg_pages, sums_per_blk;
+       int nblocks;
 
 printf("lfs_newsum\n");
 
 printf("lfs_newsum\n");
+
        lfs_endsum(fs, sp, 1);
        lfs_endsum(fs, sp, 1);
-       ++sp->sum_num;
+
+       /* Allocate a new buffer if necessary. */
        if (sp->sbp == NULL) {
        if (sp->sbp == NULL) {
-               /* Allocate a new buffer. */
+               /* Allocate a new segment if necessary. */
                if (sp->seg_bytes_left < fs->lfs_bsize) {
                        lfs_writeseg(fs, sp);
                        sp = lfs_newseg(fs);
                }
                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);
-               if (sp->sum_num != 0)
-                       sp->sbp->b_flags |= B_CALL;
-               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);
+
+               /* Get the next summary block. */
+               sp->sum_addr = next(fs, sp, &nblocks);
+
+               /*
+                * Get a new buffer and enter into the buffer list from
+                * the top of the list.
+                */
+               sp->sbp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] =
+                   lfs_newbuf(fs, sp->sum_addr, fs->lfs_bsize);
+
                sp->seg_bytes_left -= fs->lfs_bsize;
                sp->seg_bytes_left -= fs->lfs_bsize;
+
+               /*
+                * Do a callback for all but the very last summary block in
+                * the segment, for which we wait.
+                */
+               if (sp->nsums != 0)
+                       sp->sbp->b_flags |= B_CALL;
+               /*
+                * Fill in the block from the end.  The summary block is filled
+                * in from the end to the beginning so that the last summary
+                * is the last thing written, verifying the entire block.  This
+                * should go away when fragments are available.
+                */
                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;
                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;
+
+               printf("alloc summary: bp %x, lblkno %x, bp index %d\n",
+                   sp->sbp, sp->sbp->b_lblkno, fs->lfs_ssize - nblocks);
        } else {
                sp->segsum -= LFS_SUMMARY_SIZE;
                sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE;
        }
        } else {
                sp->segsum -= LFS_SUMMARY_SIZE;
                sp->sum_addr -= LFS_SUMMARY_SIZE / DEV_BSIZE;
        }
+       ++sp->nsums;
 
 
+       /* Set point to SEGSUM, initialize it. */
        ssp = sp->segsum;
        ssp->ss_next = fs->lfs_nextseg;
        ssp->ss_prev = fs->lfs_lastseg;
        ssp = sp->segsum;
        ssp->ss_next = fs->lfs_nextseg;
        ssp->ss_prev = fs->lfs_lastseg;
-
-       /* 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;
+       ssp->ss_nfinfo = ssp->ss_ninos = 0;
 
 
-       ssp->ss_nfinfo = 0;
-       ssp->ss_ninos = 0;
-       sp->sum_bytes_left -= LFS_SUMMARY_SIZE; 
-       sp->seg_bytes_left -= LFS_SUMMARY_SIZE; 
+       /* Set pointer to first FINFO, initialize it. */
+       sp->fip = (FINFO *)(sp->segsum + sizeof(SEGSUM));
+
+       sp->sum_bytes_left = LFS_SUMMARY_SIZE - sizeof(SEGSUM);
+       return (sp);
 }
 
 }
 
-#define seginc(fs, sn) ((sn + 1) % fs->lfs_nseg)
+#define seginc(fs, sn)         /* increment segment number */ \
+       (((sn) + 1) % (fs)->lfs_nseg)
+/*
+ * Return the next segment to write.
+ */
 static daddr_t
 lfs_nextseg(fs)
        LFS *fs;
 {
        int segnum, sn;
 static daddr_t
 lfs_nextseg(fs)
        LFS *fs;
 {
        int segnum, sn;
-       SEGUSE *sup;
 
 
-       segnum = satosn(fs, fs->lfs_nextseg);
-       for (sn = seginc(fs, segnum); sn != segnum; sn = seginc(fs, sn))
-               if (!(fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY))
-                       break;
+       segnum = sn = datosn(fs, fs->lfs_nextseg);
+       while ((sn = seginc(fs, sn)) != segnum &&
+           fs->lfs_segtab[sn].su_flags & SEGUSE_DIRTY);
 
        if (sn == segnum)
                panic("lfs_nextseg: file system full");         /* XXX */
 
        if (sn == segnum)
                panic("lfs_nextseg: file system full");         /* XXX */
-       return(sntosa(fs, sn));
+       return (sntoda(fs, sn));
 }
 
 /*
 }
 
 /*
- * Update the metadata that points to the blocks listed in the FIP
+ * Update the metadata that points to the blocks listed in the FINFO
  * array.
  */
 static void
  * array.
  */
 static void
@@ -447,84 +473,81 @@ lfs_updatemeta(fs, sp, ip, lbp, bpp, nblocks)
        int nblocks;
 {
        SEGUSE *segup;
        int nblocks;
 {
        SEGUSE *segup;
-       BUF **lbpp, *bp, *mbp;
-       daddr_t da, iblkno;
-       int db_per_fsb, error, i, oldsegnum;
+       BUF **lbpp, *bp;
+       daddr_t daddr, iblkno;
+       int db_per_fsb, error, i;
        long lbn;
 
        long lbn;
 
-printf("lfs_updatemeta of %d blocks\n", nblocks);      
-       if (nblocks == 0 && (ip->i_flag & (IMOD | IACC | IUPD | ICHG)) == 0)
+       if (nblocks == 0)
                return;
                return;
+printf("lfs_updatemeta of %d blocks\n", nblocks);
 
 
-       /* First sort the blocks and add disk addresses */
+       /* Sort the blocks and add disk addresses */
        shellsort(bpp, lbp, nblocks);
 
        db_per_fsb = 1 << fs->lfs_fsbtodb;
        shellsort(bpp, lbp, nblocks);
 
        db_per_fsb = 1 << fs->lfs_fsbtodb;
-       for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) {
+       for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) {
                (*lbpp)->b_blkno = sp->saddr;
                sp->saddr += db_per_fsb;
        }
 
                (*lbpp)->b_blkno = sp->saddr;
                sp->saddr += db_per_fsb;
        }
 
-       for (lbpp = bpp, i = 0; i < nblocks; i++, lbpp++) {
+       for (lbpp = bpp, i = 0; i < nblocks; ++i, ++lbpp) {
                lbn = lbp[i];
 printf("lfs_updatemeta: block %d\n", lbn);
                lbn = lbp[i];
 printf("lfs_updatemeta: block %d\n", lbn);
-               if (error = lfs_bmap(ip, lbn, &da))
-                   panic("lfs_updatemeta: lfs_bmap returned error");
-
-               if (da) {
-                       /* Update segment usage information */
-                       oldsegnum = (da - fs->lfs_sboffs[0]) /
-                           fsbtodb(fs, fs->lfs_ssize);
-                       segup = fs->lfs_segtab+oldsegnum;
+               if (error = lfs_bmap(ip, lbn, &daddr))
+                       panic("lfs_updatemeta: lfs_bmap");
+
+               /* Update in-core copy of old segment usage information. */
+               if (daddr != UNASSIGNED) {
+                       segup = fs->lfs_segtab + datosn(fs, daddr);
                        segup->su_lastmod = time.tv_sec;
                        segup->su_lastmod = time.tv_sec;
-                       if ((segup->su_nbytes -= fs->lfs_bsize) < 0)
-                               printf("lfs_updatemeta: negative bytes %s %d\n",
-                                       "in segment", oldsegnum);
+#ifdef DIAGNOSTIC
+                       if (segup->su_nbytes < fs->lfs_bsize) {
+                               printf("lfs: negative bytes (segment %d)\n",
+                                   segup - fs->lfs_segtab);
+                               panic("lfs: negative bytes in segment\n");
+                       }
+#endif
+                       segup->su_nbytes -= fs->lfs_bsize;
                }
 
                /*
                }
 
                /*
-                * Now change whoever points to lbn.  We could start with the
+                * Now change whomever 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
                 * smallest (most negative) block number in these if clauses,
                 * but we assume that indirect blocks are least common, and
-                * handle them separately.
+                * handle them separately.  The test for < 0 is correct and
+                * minimizes the path in the common case.
                 */
                 */
-               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");
+#define        BREAD(bno) \
+       if (error = bread(ITOV(ip), (bno), fs->lfs_bsize, NOCRED, &bp)) \
+               panic("lfs_updatemeta: bread");
 
 
-                               bp->b_un.b_daddr[-lbn % NINDIR(fs)] = 
+               if (lbn < 0)
+                       if (lbn < -NIADDR) {
+                               printf("meta: update indirect block %d\n",
+                                   D_INDIR);
+                               BREAD(D_INDIR);
+                               bp->b_un.b_daddr[-lbn % NINDIR(fs)] =
                                    (*lbpp)->b_blkno;
                                    (*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);
-                       if (error = bread(ITOV(ip), S_INDIR, fs->lfs_bsize, 
-                           NOCRED, &bp))
-                           panic("lfs_updatemeta: bread returned error");
-
+                               lfs_bwrite(bp);
+                       } else {
+                               ip->i_ib[-lbn-1] = (*lbpp)->b_blkno;
+               } else if (lbn < NDADDR) {
+                       ip->i_db[lbn] = (*lbpp)->b_blkno;
+               } else if ((lbn -= NDADDR) < NINDIR(fs)) {
+                       printf("meta: update indirect block %d\n", S_INDIR);
+                       BREAD(S_INDIR);
                        bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno;
                        bp->b_un.b_daddr[lbn] = (*lbpp)->b_blkno;
-               } else if ( (lbn = (lbn - NINDIR(fs)) / NINDIR(fs)) < 
-                           NINDIR(fs)) {
-
-                       iblkno = - (lbn + NIADDR + 1);
-printf("lfs_updatemeta: changing indirect block %d\n", iblkno);
-                       if (error = bread(ITOV(ip), iblkno, fs->lfs_bsize, 
-                           NOCRED, &bp))
-                           panic("lfs_updatemeta: bread returned error");
-
+                       lfs_bwrite(bp);
+               } else if ((lbn =
+                   (lbn - NINDIR(fs)) / NINDIR(fs)) < NINDIR(fs)) {
+                       iblkno = -(lbn + NIADDR + 1);
+                       printf("meta: update indirect block %d\n", iblkno);
+                       BREAD(iblkno);
                        bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno;
                        bp->b_un.b_daddr[lbn % NINDIR(fs)] = (*lbpp)->b_blkno;
-               }
-               else
-                       panic("lfs_updatemeta: logical block number too large");
-               if (bp)
                        lfs_bwrite(bp);
                        lfs_bwrite(bp);
+               } else
+                       panic("lfs_updatemeta: logical block number too large");
        }
 }
 
        }
 }
 
@@ -546,11 +569,11 @@ printf("lfs_writeckp\n");
         * This will write the dirty ifile blocks, but not the segusage
         * table nor the ifile inode.
         */
         * 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);
+       sp = lfs_writefile(fs, sp, 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
+        * If the segment usage table and the ifile inode won't fit in this
+        * segment, put them in the next one.
         */
        bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift;
        if (sp->ninodes % INOPB(fs) == 0)
         */
        bytes_needed = fs->lfs_segtabsz << fs->lfs_bshift;
        if (sp->ninodes % INOPB(fs) == 0)
@@ -559,14 +582,16 @@ printf("lfs_writeckp\n");
        if (sp->seg_bytes_left < bytes_needed) {
                lfs_writeseg(fs, sp);
                sp = lfs_newseg(fs);
        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);
+               ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
+       } else if (sp->sum_bytes_left < fs->lfs_segtabsz * sizeof(daddr_t)) {
+               sp = lfs_newsum(fs, sp);
+               ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
+       }
 
 #ifdef DEBUG
        if (sp->seg_bytes_left < bytes_needed)
                panic("lfs_writeckp: unable to write checkpoint");
 #endif
 
 #ifdef DEBUG
        if (sp->seg_bytes_left < bytes_needed)
                panic("lfs_writeckp: unable to write checkpoint");
 #endif
-
        /*
         * Update the segment usage information and the ifile inode
         * and write it out.
        /*
         * Update the segment usage information and the ifile inode
         * and write it out.
@@ -577,122 +602,146 @@ printf("lfs_writeckp\n");
        sup->su_lastmod = time.tv_sec;
        sup->su_flags = SEGUSE_DIRTY;
 
        sup->su_lastmod = time.tv_sec;
        sup->su_flags = SEGUSE_DIRTY;
 
-       /* Get buffers for the segusage table and write it out. */
+       /*
+        * Get buffers for the segusage table and write it out.  Don't
+        * bother updating the FINFO pointer, it's not used after this.
+        */
        ip = VTOI(fs->lfs_ivnode);
        fip = sp->fip;
        lbp = &fip->fi_blocks[fip->fi_nblocks];
        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++) {
+       for (xp = fs->lfs_segtab, i = 0; i < fs->lfs_segtabsz;
+           xp += fs->lfs_bsize, ++i, ++lbp) {
                *sp->cbpp++ = bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize);
                bp->b_flags |= B_CALL;
                *sp->cbpp++ = bp = lfs_newbuf(fs, sp->saddr, fs->lfs_bsize);
                bp->b_flags |= B_CALL;
-               bcopy(xp, bp->b_un.b_words, fs->lfs_bsize);
-               ip->i_din.di_db[i] = sp->saddr;
+               bcopy(xp, bp->b_un.b_addr, fs->lfs_bsize);
+               ip->i_db[i] = sp->saddr;
                sp->saddr += (1 << fs->lfs_fsbtodb);
                *lbp = i;
                sp->saddr += (1 << fs->lfs_fsbtodb);
                *lbp = i;
-               fip->fi_nblocks++;
+               ++fip->fi_nblocks;
        }
        }
-       sp = lfs_writeinode(fs, sp, fs->lfs_ivnode);
-       lfs_writeseg(fs, sp);
-       return (sp);
+       return (lfs_writeinode(fs, sp, VTOI(fs->lfs_ivnode)));
 }
 
 /*
 }
 
 /*
- * 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.
+ * Write the dirty blocks associated with a vnode.
  */
 static SEGMENT *
  */
 static SEGMENT *
-lfs_writefile(sp, fs, vp, do_ckp)
-       SEGMENT *sp;
+lfs_writefile(fs, sp, vp, do_ckp)
        LFS *fs;
        LFS *fs;
+       SEGMENT *sp;
        VNODE *vp;
        int do_ckp;
 {
        FINFO *fip;
        ino_t inum;
 
        VNODE *vp;
        int do_ckp;
 {
        FINFO *fip;
        ino_t inum;
 
-       /* Initialize the FINFO structure. */
        inum = VTOI(vp)->i_number;
        inum = VTOI(vp)->i_number;
-printf("lfs_writefile: node %d\n", inum);
-       sp->fip->fi_ino = inum;
-       sp->fip->fi_nblocks = 0;
-       sp->fip->fi_version =
-           inum == LFS_IFILE_INUM ? 1 : lfs_getversion(fs, inum);
-
-       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);
-       }
+       printf("lfs_writefile: node %d\n", inum);
+
+       if (vp->v_dirtyblkhd != NULL) {
+               if (sp->seg_bytes_left < fs->lfs_bsize) {
+                       lfs_writeseg(fs, sp);
+                       sp = lfs_newseg(fs);
+               } else if (sp->sum_bytes_left < sizeof(FINFO))
+                       sp = lfs_newsum(fs, sp);
+               sp->sum_bytes_left -= sizeof(FINFO) - sizeof(daddr_t);
+
+               fip = sp->fip;
+               fip->fi_nblocks = 0;
+               fip->fi_version =
+                   inum == LFS_IFILE_INUM ? 1 : lfs_getversion(fs, inum);
+               fip->fi_ino = inum;
+
+               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);
+               }
 
 
-(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 (inum != LFS_IFILE_INUM) {
-               sp = lfs_writeinode(fs, sp, vp);
                fip = sp->fip;
                fip = sp->fip;
-               if (fip->fi_nblocks) {
-                       ((SEGSUM *)(sp->segsum))->ss_nfinfo++;
-                       sp->fip = (FINFO *)((u_long)fip + sizeof(FINFO) + 
-                           sizeof(u_long) * fip->fi_nblocks - 1);
+               printf("lfs_writefile: adding %d blocks\n", fip->fi_nblocks);
+
+               /*
+                * If this is the ifile, always update the file count as we'll
+                * be adding the segment usage information even if we didn't
+                * write any blocks.  Also, don't update the FINFO pointer for
+                * the ifile as the segment usage information hasn't yet been
+                * added.
+                */
+               if (inum == LFS_IFILE_INUM)
+                       ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
+               else if (fip->fi_nblocks != 0) {
+                       ++((SEGSUM *)(sp->segsum))->ss_nfinfo;
+                       sp->fip = (FINFO *)((caddr_t)fip + sizeof(FINFO) +
+                           sizeof(daddr_t) * (fip->fi_nblocks - 1));
                }
        }
                }
        }
-       return(sp);
+
+       /* If this isn't the ifile, update the inode. */
+       if (inum != LFS_IFILE_INUM)
+               sp = lfs_writeinode(fs, sp, VTOI(vp));
+       return (sp);
 }
 
 static SEGMENT *
 }
 
 static SEGMENT *
-lfs_writeinode(fs, sp, vp)
+lfs_writeinode(fs, sp, ip)
        LFS *fs;
        SEGMENT *sp;
        LFS *fs;
        SEGMENT *sp;
-       VNODE *vp;
+       INODE *ip;
 {
        BUF *bp;
 {
        BUF *bp;
-       INODE *ip;
-       SEGSUM *ssp;
-       daddr_t iaddr, next_addr;
-       int npages, nseg_pages, sums_per_blk;
-       struct dinode *dip;
+       daddr_t next_addr;
+       int nblocks;
 
 printf("lfs_writeinode\n");
 
 printf("lfs_writeinode\n");
-       sums_per_blk = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+       /* Allocate a new inode block if necessary. */
        if (sp->ibp == NULL) {
        if (sp->ibp == NULL) {
-               /* Allocate a new buffer. */
+               /* Allocate a new segment if necessary. */
                if (sp->seg_bytes_left < fs->lfs_bsize) {
                        lfs_writeseg(fs, sp);
                        sp = lfs_newseg(fs);
                }
                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);
+
+               /* Get next inode block. */
+               next_addr = next(fs, sp, &nblocks);
+
+               /*
+                * Get a new buffer and enter into the buffer list from
+                * the top of the list.
+                */
+               sp->ibp = sp->bpp[fs->lfs_ssize - (nblocks + 1)] =
+                   lfs_newbuf(fs, next_addr, fs->lfs_bsize);
                sp->ibp->b_flags |= B_CALL;
                sp->ibp->b_flags |= B_CALL;
-               sp->bpp[fs->lfs_ssize - npages] = sp->ibp;
+
+               /* Set remaining space counter. */
                sp->seg_bytes_left -= fs->lfs_bsize;
                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);
+
+               printf("alloc inode: bp %x, lblkno %x, bp index %d\n",
+                   sp->sbp, sp->sbp->b_lblkno, fs->lfs_ssize - nblocks);
        }
        }
-       ip = VTOI(vp);
+
+       /* Copy the new inode onto the inode page. */
        bp = sp->ibp;
        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)
+       bcopy(&ip->i_din,
+           bp->b_un.b_dino + (sp->ninodes % INOPB(fs)), sizeof(DINODE));
+
+       /* Increment inode count in segment summary block. */
+       ++((SEGSUM *)(sp->segsum))->ss_ninos;
+
+       /* If this page is full, set flag to allocate a new page. */
+       if (++sp->ninodes % INOPB(fs) == 0)
                sp->ibp = NULL;
                sp->ibp = NULL;
+
+       /*
+        * If updating the ifile, update the super-block; otherwise, update
+        * the ifile itself.  In either case, turn of inode update flags.
+        */
        if (ip->i_number == LFS_IFILE_INUM)
        if (ip->i_number == LFS_IFILE_INUM)
-               fs->lfs_idaddr = iaddr;
+               fs->lfs_idaddr = bp->b_blkno;
        else
        else
-               lfs_iset(ip, iaddr, ip->i_atime);       /* Update ifile */
-       ip->i_flags &= ~(IMOD|IACC|IUPD|ICHG);          /* make inode clean */
-       return(sp);
+               lfs_iset(ip, bp->b_blkno, ip->i_atime);
+       ip->i_flags &= ~(IMOD | IACC | IUPD | ICHG);
+       return (sp);
 }
 
 static void
 }
 
 static void
@@ -701,35 +750,27 @@ lfs_writeseg(fs, sp)
        SEGMENT *sp;
 {
        BUF **bpp;
        SEGMENT *sp;
 {
        BUF **bpp;
-       SEGSUM *ssp;
        SEGUSE *sup;
        SEGUSE *sup;
-       VNODE *devvp;
-       int nblocks, nbuffers, ninode_blocks, nsegsums, nsum_pb;
-       int i, metaoff, nmeta, s;
+       int i, nblocks, s, (*strategy) __P((BUF *));
+       void *pmeta;
 
 printf("lfs_writeseg\n");
 
 printf("lfs_writeseg\n");
-       fs->lfs_lastseg = sntosa(fs, sp->seg_number);
+       /* Update superblock segment address. */
+       fs->lfs_lastseg = sntoda(fs, sp->seg_number);
+
+       /* Finish up any summary block. */
        lfs_endsum(fs, sp, 0);
 
        /*
         * Copy inode and summary block buffer pointers down so they are
         * contiguous with the page buffer pointers.
         */
        lfs_endsum(fs, sp, 0);
 
        /*
         * Copy inode and summary block buffer pointers down so they are
         * contiguous with the page buffer pointers.
         */
-       ssp = sp->segsum;
-       nsum_pb = fs->lfs_bsize / LFS_SUMMARY_SIZE;
-       nbuffers = sp->cbpp - sp->bpp;
-       /*
-        * XXX
-        * Why isn't this (sp->sum_num + nsum_pb - 1) / nsum_pb;
-        */
-       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;
-       nblocks = nbuffers + nmeta;
-       if (sp->bpp + metaoff != sp->cbpp)
-               bcopy(sp->bpp + metaoff, sp->cbpp, sizeof(BUF *) * nmeta);
-       sp->cbpp += nmeta;
+       (void)next(fs, sp, &nblocks);
+       pmeta = (sp->bpp + fs->lfs_ssize) - nblocks;
+       if (pmeta != sp->cbpp)
+               bcopy(pmeta, sp->cbpp, sizeof(BUF *) * nblocks);
+       sp->cbpp += nblocks;
+       nblocks = sp->cbpp - sp->bpp;
 
        sup = fs->lfs_segtab + sp->seg_number;
        sup->su_nbytes = nblocks << fs->lfs_bshift;
 
        sup = fs->lfs_segtab + sp->seg_number;
        sup->su_nbytes = nblocks << fs->lfs_bshift;
@@ -742,8 +783,7 @@ printf("lfs_writeseg\n");
         * then, after they've completed, the summary buffer.  Only when that
         * final write completes is the segment valid.
         */
         * then, after they've completed, the summary buffer.  Only when that
         * final write completes is the segment valid.
         */
-       devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
-       --nblocks;                              /* Don't count summary. */
+       --nblocks;                      /* Don't count last summary block. */
 
        sp->nextp = fs->lfs_seglist;
        fs->lfs_seglist = sp;
 
        sp->nextp = fs->lfs_seglist;
        fs->lfs_seglist = sp;
@@ -751,8 +791,11 @@ printf("lfs_writeseg\n");
        s = splbio();
        fs->lfs_iocount += nblocks;
        splx(s);
        s = splbio();
        fs->lfs_iocount += nblocks;
        splx(s);
+
+       strategy =
+           VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
        for (bpp = sp->bpp, i = 0; i < nblocks; ++i, ++bpp)
        for (bpp = sp->bpp, i = 0; i < nblocks; ++i, ++bpp)
-               (devvp->v_op->vop_strategy)(*bpp);
+               (strategy)(*bpp);
 }
 
 static void
 }
 
 static void
@@ -761,77 +804,118 @@ lfs_writesum(fs)
 {
        BUF *bp;
        SEGMENT *next_sp, *sp;
 {
        BUF *bp;
        SEGMENT *next_sp, *sp;
-       VNODE *devvp;
+       int (*strategy) __P((BUF *));
 
 printf("lfs_writesum\n");
 
 printf("lfs_writesum\n");
-       devvp = NULL;
+       strategy =
+           VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
        for (sp = fs->lfs_seglist; sp; sp = next_sp) {
                bp = *(sp->cbpp - 1);
        for (sp = fs->lfs_seglist; sp; sp = next_sp) {
                bp = *(sp->cbpp - 1);
-               if (devvp == NULL)
-                       devvp = VFSTOUFS(bp->b_vp->v_mount)->um_devvp;
-               (devvp->v_op->vop_strategy)(bp);
+               (strategy)(bp);
                biowait(bp);
                next_sp = sp->nextp;
                free(sp->bpp, M_SEGMENT);
                free(sp, M_SEGMENT);
        }
                biowait(bp);
                next_sp = sp->nextp;
                free(sp->bpp, M_SEGMENT);
                free(sp, M_SEGMENT);
        }
+       /* Segment list is done. */
+       fs->lfs_seglist = NULL;
 }
 
 static void
 }
 
 static void
-lfs_writesuper(fs, sp)
+lfs_writesuper(fs)
        LFS *fs;
        LFS *fs;
-       SEGMENT *sp;
 {
        BUF *bp;
 {
        BUF *bp;
-       VNODE *devvp;
+       int (*strategy) __P((BUF *));
 
 printf("lfs_writesuper\n");
 
 printf("lfs_writesuper\n");
-       /* Get a buffer for the super block */
+       /* Checksum the superblock and copy it into a buffer. */
        fs->lfs_cksum = cksum(fs, sizeof(LFS) - sizeof(fs->lfs_cksum));
        bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD);
        bcopy(fs, bp->b_un.b_lfs, sizeof(LFS));
 
        fs->lfs_cksum = cksum(fs, sizeof(LFS) - sizeof(fs->lfs_cksum));
        bp = lfs_newbuf(fs, fs->lfs_sboffs[0], LFS_SBPAD);
        bcopy(fs, bp->b_un.b_lfs, sizeof(LFS));
 
-       /* Write the first superblock; wait. */
-       devvp = VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp;
-       (devvp->v_op->vop_strategy)(bp);
+       /* Write the first superblock. */
+       strategy =
+           VFSTOUFS(fs->lfs_ivnode->v_mount)->um_devvp->v_op->vop_strategy;
+       (strategy)(bp);
        biowait(bp);
        biowait(bp);
-       
-       /* Now, write the second one for which we don't have to wait */
+
+       /* Write the second superblock. */
        bp->b_flags &= ~B_DONE;
        bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1];
        bp->b_flags &= ~B_DONE;
        bp->b_blkno = bp->b_lblkno = fs->lfs_sboffs[1];
-       (devvp->v_op->vop_strategy)(bp);
+       (strategy)(bp);
 
        bp->b_vp = NULL;                        /* No associated vnode. */
 
        bp->b_vp = NULL;                        /* No associated vnode. */
+       biowait(bp);
        brelse(bp);
        brelse(bp);
+printf("lfs_writesuper is returning\n");
 }
 
 }
 
-/* Block match routines used when traversing the dirty block chain. */
+/*
+ * Logical block number match routines used when traversing the dirty block
+ * chain.
+ */
+int
 match_data(bp)
        BUF *bp;
 {
 match_data(bp)
        BUF *bp;
 {
-       return(bp->b_lblkno >= 0);
+       return (bp->b_lblkno >= 0);
 }
 
 }
 
+int
 match_dindir(bp)
        BUF *bp;
 {
 match_dindir(bp)
        BUF *bp;
 {
-       return(bp->b_lblkno == D_INDIR);
+       return (bp->b_lblkno == D_INDIR);
 }
 
 /*
  * These are single indirect blocks.  There are three types:
 }
 
 /*
  * 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.
+ *
+ * the one in the inode (lblkno == S_INDIR, or -1).
+ * the ones that hang off of the double indirect in the inode (D_INDIR);
+ *    these all have addresses in the range -2NINDIR to -(3NINDIR-1).
+ * the ones that hang off of the double indirect that hangs off of the
+ *    triple indirect.  These all have addresses < -(NINDIR^2).
+ *
+ * Since we currently don't support triple indirect blocks, this gets
+ * simpler, and we just look for block numbers less than -NIADDR.
  */
  */
+int
 match_indir(bp)
        BUF *bp;
 {
 match_indir(bp)
        BUF *bp;
 {
-       return(bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR);
+       return (bp->b_lblkno == S_INDIR || bp->b_lblkno < -NIADDR);
+}
+
+/* Get the next inode/summary block. */
+static daddr_t
+next(fs, sp, nbp)
+       LFS *fs;
+       SEGMENT *sp;
+       int *nbp;
+{
+       int nblocks, nino_blocks, nseg_blocks, sums_per_block;
+
+       /* Fs blocks allocated to summary blocks. */
+       sums_per_block = fs->lfs_bsize / LFS_SUMMARY_SIZE;
+       nseg_blocks = (sp->nsums + sums_per_block - 1) / sums_per_block;
+
+       /* Fs blocks allocated to inodes. */
+       nino_blocks = (sp->ninodes + INOPB(fs) - 1) / INOPB(fs);
+
+       /* Total number of fs blocks allocated. */
+       nblocks = nseg_blocks + nino_blocks;
+
+       if (nbp)
+               *nbp = nblocks;
+
+       /*
+        * The disk address of the new inode/summary block is the address of
+        * the start of the segment after this one minus the number of blocks
+        * that we've already used.
+        */
+       return (sntoda(fs, sp->seg_number + 1) - fsbtodb(fs, nblocks + 1));
 }
 
 /*
 }
 
 /*