Version 2 cleaner
authorKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 7 Aug 1992 03:27:22 +0000 (19:27 -0800)
committerKeith Bostic <bostic@ucbvax.Berkeley.EDU>
Fri, 7 Aug 1992 03:27:22 +0000 (19:27 -0800)
SCCS-vsn: libexec/lfs_cleanerd/clean.h 1.2
SCCS-vsn: libexec/lfs_cleanerd/library.c 1.2

usr/src/libexec/lfs_cleanerd/clean.h
usr/src/libexec/lfs_cleanerd/library.c

index d3ab994..9638974 100644 (file)
@@ -4,6 +4,11 @@
  * for finding and parsing LFS segments.
  */
 
  * for finding and parsing LFS segments.
  */
 
+#define DUMP_SUM_HEADER                0x0001
+#define DUMP_INODE_ADDRS       0x0002
+#define DUMP_FINFOS            0x0004
+#define        DUMP_ALL                0xFFFF
+
 #define IFILE_NAME "ifile"
 
 #ifndef TRUE
 #define IFILE_NAME "ifile"
 
 #ifndef TRUE
 #define FALSE  (0)
 #endif
 
 #define FALSE  (0)
 #endif
 
+/*
+ * Cleaner parameters
+ *     BUSY_LIM: lower bound of the number of segments currently available
+ *             as a percentage of the total number of free segments possibly
+ *             available.
+ *     IDLE_LIM: Same as BUSY_LIM but used when the system is idle.
+ *     MIN_SEGS: Minimum number of segments you should always have.
+ *             I have no idea what this should be, but it should probably
+ *             be a function of lfsp.
+ *     NUM_TO_CLEAN: Number of segments to clean at once.  Again, this
+ *             should probably be based on the file system size and how
+ *             full or empty the segments being cleaned are.
+ */
+
+#define        BUSY_LIM        0.50
+#define        IDLE_LIM        0.90
+#define        MIN_SEGS(lfsp)  (3)
+#define        NUM_TO_CLEAN(fsp)       (5)
+
+#define MAXLOADS       3
+#define        ONE_MIN 0
+#define        FIVE_MIN 1
+#define        FIFTEEN_MIN 2
+
 typedef struct fs_info {
        struct  statfs  *fi_statfsp;    /* fsstat info from getfsstat */
 typedef struct fs_info {
        struct  statfs  *fi_statfsp;    /* fsstat info from getfsstat */
-       struct  lfs     *fi_lfsp;       /* superblock */
-                                       /*
-                                        * shared cleaner info data 
-                                        * (from top of ifile) 
-                                        */
-       CLEANERINFO     *fi_cip;
+       struct  lfs     fi_lfs;         /* superblock */
+       CLEANERINFO     *fi_cip;        /* Cleaner info from ifile */
        SEGUSE  *fi_segusep;            /* segment usage table (from ifile) */
        IFILE   *fi_ifilep;             /* ifile table (from ifile) */
        u_long  fi_daddr_shift;         /* shift to get byte offset of daddr */
        u_long  fi_ifile_count;         /* # entries in the ifile table */
        SEGUSE  *fi_segusep;            /* segment usage table (from ifile) */
        IFILE   *fi_ifilep;             /* ifile table (from ifile) */
        u_long  fi_daddr_shift;         /* shift to get byte offset of daddr */
        u_long  fi_ifile_count;         /* # entries in the ifile table */
-       u_long  fi_ifile_length;        /* length of the ifile */
+       off_t   fi_ifile_length;        /* length of the ifile */
 } FS_INFO;
 
 } FS_INFO;
 
-
-#define fsid           (fsp->fi_statfsp->f_fsid)
-#define statfsp                (fsp->fi_statfsp)
-#define lfsp           (fsp->fi_lfsp)
-#define cip            (fsp->fi_cip)
-#define segusep                (fsp->fi_segusep)
-#define ifilep         (fsp->fi_ifilep)
-#define ifile_count    (fsp->fi_ifile_count)
-#define ifile_length   (fsp->fi_ifile_length)
-
 /* 
  * XXX: size (in bytes) of a segment
  *     should lfs_bsize be fsbtodb(fs,1), blksize(fs), or lfs_dsize? 
  */
 /* 
  * XXX: size (in bytes) of a segment
  *     should lfs_bsize be fsbtodb(fs,1), blksize(fs), or lfs_dsize? 
  */
-#define seg_size(fs) ((fs)->lfs_ssize<<(fs)->lfs_bshift)
+#define seg_size(fs) ((fs)->lfs_ssize << (fs)->lfs_bshift)
 
 /* daddr -> byte offset */
 
 /* daddr -> byte offset */
-#define datobyte(fs, da) ((da)<<(fs)->fi_daddr_shift)
-#define bytetoda(fs, byte) ((byte)>>(fs)->fi_daddr_shift)
-
-#define CLEANSIZE(fs)  (CLEANSIZE_SU(fs) << fs->lfs_bshift)
-#define SEGTABSIZE(fs) (SEGTABSIZE_SU(fs) << fs->lfs_bshift)
-
-#define IFILE_ENTRY(fs, if, i) ((IFILE*)((caddr_t)(if) + \
-       (fs)->lfs_bsize*((i)/(fs)->lfs_ifpb) + \
-       sizeof(IFILE)*((i)%(fs)->lfs_ifpb)))
-#define SEGUSE_ENTRY(fs, su, i) ((SEGUSE*)((caddr_t)(su) + \
-       (fs)->lfs_bsize*((i)/(fs)->lfs_sepb) + \
-       sizeof(IFILE)*((i)%(fs)->lfs_sepb)))
-
-/*
- * fs_getmntinfo:
- *
- *    This function will get information on all mounted file systems
- * with the given type.  It will return the number of mounted file
- * systems with the right type.  It will return in *buf a pointer to
- * the array of statfs structures.
- */
-extern int
-fs_getmntinfo __P((struct statfs **buf, int type));
+#define datobyte(fs, da) ((da) << (fs)->fi_daddr_shift)
+#define bytetoda(fs, byte) ((byte) >> (fs)->fi_daddr_shift)
+
+#define CLEANSIZE(fsp) (fsp->fi_lfs.lfs_cleansz << fsp->fi_lfs.lfs_bshift)
+#define SEGTABSIZE(fsp)        (fsp->fi_lfs.lfs_segtabsz << fsp->fi_lfs.lfs_bshift)
+
+#define IFILE_ENTRY(fs, if, i) \
+       ((IFILE *)((caddr_t)(if) + ((i) / (fs)->lfs_ifpb << (fs)->lfs_bshift)) \
+       + (i) % (fs)->lfs_ifpb)
+
+#define SEGUSE_ENTRY(fs, su, i) \
+       ((SEGUSE *)((caddr_t)(su) + (fs)->lfs_bsize * ((i) / (fs)->lfs_sepb)) +\
+       (i) % (fs)->lfs_sepb)
+
+__BEGIN_DECLS
+int     dump_summary __P((struct lfs *, SEGSUM *, u_long, daddr_t **));
+void    err __P((const int, const char *, ...));
+int     fs_getmntinfo __P((struct statfs **, int));
+int     get __P((int, off_t, void *, size_t));
+FS_INFO        *get_fs_info __P((struct statfs *, int));
+int     lfs_segmapv __P((FS_INFO *, int, caddr_t, BLOCK_INFO **, int *,
+            INODE_INFO **, int *));
+int     mmap_segment __P((FS_INFO *, int, caddr_t *));
+void    munmap_segment __P((FS_INFO *, caddr_t));
+void    reread_fs_info __P((FS_INFO *, int));
+void    toss __P((void *, int *, size_t,
+             int (*)(const void *, const void *, const void *), void *));
 
 /*
 
 /*
- * get_fs_info:
- *
- * get all the information available on a file system
- */
-extern int
-get_fs_info __P((struct statfs *lstatfsp, FS_INFO **fspp, int count));
-
-extern void
-free_fs_info __P((FS_INFO *fsp, int count));
-
-/* 
- * get_superblock: 
- *    gets the superblock from disk (possibly in face of errors) 
- */
-extern int
-get_superblock __P((FS_INFO *fsp, struct lfs *sbp));
-
-
-/* 
- * get_ifile: 
- *    This function will map the ifile into memory.  It returns
- * NULL on failure.
- */
-extern int
-get_ifile __P((FS_INFO *fsp));
-
-/*
- * segmapv:
- *
- *   This function will scan a segment and return a list of
- * <inode, blocknum> pairs which indicate which blocks were
- * contained as live data within the segment at some point
- * (it may have "died" since then).  Any given pair will be 
- * listed at most once.
- */
-extern int 
-lfs_segmapv __P((FS_INFO *fsp, int seg, caddr_t seg_buf, 
-               BLOCK_INFO **blocks, int *bcount, 
-               INODE_INFO **inodes, int *icount));
-
-/* 
- * this will parse a partial segment and create a vector of block_info's
- * for live data blocks for live inodes.  It will not include blocks or 
- * inodes from files with new version numbers.  
- */
-extern void
-pseg_blocks __P((FS_INFO *fsp, int seg, SEGSUM *s, caddr_t seg_buf, 
-               BLOCK_INFO **blocks, int *count));
-
-/* 
- * this will parse a partial segment and create a vector of inode_info's
- * for live inodes.  It will not include blocks or inodes from files 
- * with new version numbers.  
- */
-extern void
-pseg_inodes __P((FS_INFO *fsp, int seg, SEGSUM *s, caddr_t seg_buf, 
-               INODE_INFO **inodes, int *count));
-
-/* 
- * return the size of the partial segment in bytes. 
- */
-extern u_long
-pseg_size __P((FS_INFO *fsp, SEGSUM *s));
-
-
-/* 
- * join block list b with list a (eliminating duplicates), leaving result
- * in list a.
- */
-extern void
-pseg_bjoin __P((FS_INFO *fsp, BLOCK_INFO **ablocks, int *acount, 
-               BLOCK_INFO *bblocks, int bcount));
-
-
-/* 
- * join inode list b with list a (eliminating duplicates), leaving result
- * in list a.
- */
-extern void
-pseg_ijoin __P((FS_INFO *fsp, INODE_INFO **ainodes, int *acount, 
-               INODE_INFO *binodes, int bcount));
-
-
-/* is the segsum block valid? return TRUE if it is, FALSE otherwise */
-extern int 
-segsum_valid __P((FS_INFO *fsp, SEGSUM *ssp));
-
-
-/*
- * pseg_valid:
- *
- * returns 1 if the partial segment is valid, and 0 if it is invalid.
- * it uses the checksums to verify validity.
- */     
-extern int
-pseg_valid __P((FS_INFO *fsp, SEGSUM *ssp));
-
-
-/* 
- * pseg_finfos:
- * 
- * get array of FINFO pointers for partial segment
- * return the array in finfos, and the size of the array in count
- */
-extern void
-pseg_finfos __P((FS_INFO *fsp, SEGSUM *ssp, FINFO ***finfos, int *count));
-
-/*
- * blocksize:
- *
- * returns the size (in bytes) of a (logical) block.
- * this is used because lfs uses different block sizes, depending
- * on the logical # of the block.  Lfs uses various sizes so
- * it doesn't need fragments.
- */ 
-extern u_long
-blocksize __P((FS_INFO *fsp, int index));
-
-/*
- * finfo_size:
- *
- * returns the size in bytes of an FINFO structure 
- */
-extern u_long
-finfo_size __P((FINFO *finfop));
-       
-/*
- * Simple, general purpose, fast checksum.  Data must be short-aligned.
- * Returns a u_long in case we ever want to do something more rigorous.
- *
- * XXX
- * Use the TCP/IP checksum instead.
- */
-extern u_long
-cksum __P((register void *str, register size_t len));
-
-/* 
- * read a segment into a memory buffer
- */
-extern int
-mmap_segment __P((FS_INFO *fsp, int segment, caddr_t *seg_buf));
-
-extern void
-munmap_segment __P((FS_INFO *fsp, caddr_t seg_buf));
-
-
-/*
- * USEFUL DEBUGGING TOOLS:
- */
-
-extern void
-print_IFILE __P((IFILE *p));
-
-extern void
-print_SEGUSE __P((SEGUSE *p));
-
-extern void
-print_CLEANERINFO __P((CLEANERINFO *p));
-
-extern void
-print_SEGSUM __P((SEGSUM *p));
-
-extern void
-print_time_t __P((time_t t));
-
-extern void
-print_BLOCK_INFO __P((BLOCK_INFO *p));
-
-extern void
-print_INODE_INFO __P((INODE_INFO *p));
-
-extern void
-print_FINFO __P((FINFO *p));
-
-extern void
-print_lfs __P((struct lfs *p));
+ * USEFUL DEBUGGING FUNCTIONS:
+ */
+#ifdef VERBOSE
+#define PRINT_FINFO(fp, ip) { \
+       (void)printf("    %s %s%d version %d nblocks %d\n", \
+           (ip)->if_version > (fp)->fi_version ? "TOSSING" : "KEEPING", \
+           "FINFO for inode: ", (fp)->fi_ino, \
+           (fp)->fi_version, (fp)->fi_nblocks); \
+       fflush(stdout); \
+}
+
+#define PRINT_IINFO(b, iip) { \
+       (void) printf("\t%s inode: %d daddr: 0x%lx create: %s\n", \
+           b ? "KEEPING" : "TOSSING", (iip)->ii_inode, (iip)->ii_daddr, \
+           ctime((time_t *)&(iip)->ii_segcreate)); \
+       fflush(stdout); \
+}
+
+#define PRINT_BINFO(bip) { \
+       (void)printf("\tinode: %d lbn: %d daddr: 0x%lx create: %s\n", \
+           (bip)->bi_inode, (bip)->bi_lbn, (bip)->bi_daddr, \
+           ctime((time_t *)&(bip)->bi_segcreate)); \
+       fflush(stdout); \
+}
+
+#define PRINT_SEGUSE(sup, n) { \
+       (void)printf("Segment %d nbytes=%lu\tflags=%c%c%c ninos=%d nsums=%d lastmod: %s\n", \
+                       n, (sup)->su_nbytes, \
+                       (sup)->su_flags & SEGUSE_DIRTY ? 'D' : 'C', \
+                       (sup)->su_flags & SEGUSE_ACTIVE ? 'A' : ' ', \
+                       (sup)->su_flags & SEGUSE_SUPERBLOCK ? 'S' : ' ', \
+                       (sup)->su_ninos, (sup)->su_nsums, \
+                       ctime((time_t *)&(sup)->su_lastmod)); \
+       fflush(stdout); \
+}
+
+void    dump_super __P((struct lfs *));
+void    dump_cleaner_info __P((void *));
+void    print_SEGSUM __P(( struct lfs *, SEGSUM *));
+void    print_CLEANERINFO __P((CLEANERINFO *));
+#else
+#define        PRINT_FINFO(fp, ip)
+#define        PRINT_IINFO(b, iip)
+#define PRINT_BINFO(bip)
+#define        PRINT_SEGUSE(sup, n)
+#define        dump_cleaner_info(cip)
+#define        dump_super(lfsp)
+#endif
 
 
+__END_DECLS
index 6af4c2d..4b36fa6 100644 (file)
@@ -1,24 +1,32 @@
-
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/param.h>
 #include <sys/time.h>
-#include <sys/uio.h>
-#include <sys/vnode.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/lfs/lfs.h>
 #include <sys/stat.h>
 #include <sys/mount.h>
 
 #include <ufs/ufs/dinode.h>
 #include <ufs/lfs/lfs.h>
-#include <ufs/lfs/lfs_extern.h>
 
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
 
 #include <fcntl.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 #include "clean.h"
 
 #include "clean.h"
 
+void    add_blocks __P((FS_INFO *, BLOCK_INFO *, int *, SEGSUM *, caddr_t,
+            daddr_t, daddr_t));
+void    add_inodes __P((FS_INFO *, INODE_INFO *, int *, SEGSUM *, caddr_t,
+            daddr_t));
+int     bi_compare __P((const void *, const void *));
+int     bi_toss __P((const void *, const void *, const void *));
+void    get_ifile __P((FS_INFO *));
+int     get_superblock __P((FS_INFO *, struct lfs *));
+int     ii_compare __P((const void *, const void *));
+int     ii_toss __P((const void *, const void *, const void *));
+int     pseg_valid __P((FS_INFO *, SEGSUM *));
+
 /*
 /*
- * fs_getmntinfo:
- *
- *    This function will get information on all mounted file systems
+ * This function will get information on all mounted file systems
  * of a given type.
  */
 int
  * of a given type.
  */
 int
@@ -26,749 +34,507 @@ fs_getmntinfo(buf, type)
        struct  statfs  **buf;
        int     type;
 {
        struct  statfs  **buf;
        int     type;
 {
-       int     i;
-       int     count;
-       int     tcount;
-       struct  statfs  *tstatfsp;
+       struct statfs *tstatfsp;
+       struct statfs *sbp;
+       int count, i, tcount;
 
        tcount = getmntinfo(&tstatfsp, 0);
 
        if (tcount < 0) {
 
        tcount = getmntinfo(&tstatfsp, 0);
 
        if (tcount < 0) {
-               perror ("fs_getmntinfo: getmntinfo failed");
-               return -1;
+               err(0, "getmntinfo failed");
+               return (-1);
        }
 
        }
 
-       for (count = 0, i = 0 ; i < tcount ; i ++)
-               if (type == 0 || tstatfsp[i].f_type == type)
-                       ++ count;
-
-       if (count > 0) {
-               *buf = (struct statfs *)
-                       malloc(count*sizeof(struct statfs));
-               if (*buf == 0) { perror ("fs_getmntinfo: out of space"); exit (1); }
-               for (i = 0, count = 0 ; i < tcount ; i ++) {
-                       if (type == 0 || tstatfsp[i].f_type == type) {
-                               (*buf)[count] = tstatfsp[i];
-                               ++count;
+       for (count = 0, i = 0; i < tcount ; ++i)
+               if (tstatfsp[i].f_type == type)
+                       ++count;
+
+       if (count) {
+               if (!(*buf = (struct statfs *)
+                       malloc(count * sizeof(struct statfs))))
+                       err(1, "fs_getmntinfo: out of space");
+               for (i = 0, sbp = *buf; i < tcount ; ++i) {
+                       if (tstatfsp[i].f_type == type) {
+                               *sbp = tstatfsp[i];
+                               ++sbp;
                        }
                }
                        }
                }
-               return count;
        }
        }
-       return 0;
+       return (count);
 }
 
 /*
 }
 
 /*
- * get_fs_info:
- *
- * get all the information available on a file system
+ * Get all the information available on an LFS file system.
+ * Returns an array of FS_INFO structures, NULL on error.
  */
  */
-int
-get_fs_info (lstatfsp, fspp, count)
-       struct  statfs  *lstatfsp;      /* IN: array of statfs structs */
-       FS_INFO **fspp;                 /* OUT: resulting array of FS_INFOs */
-       int     count;                  /* IN: number of file systems */
+FS_INFO *
+get_fs_info (lstatfsp, count)
+       struct statfs *lstatfsp;        /* IN: array of statfs structs */
+       int count;                      /* IN: number of file systems */
 {
 {
+       FS_INFO *fp, *fsp;
        int     i;
        int     i;
-       caddr_t ifp;
-       FS_INFO *fsp;
        
        
-       *fspp = (FS_INFO *)malloc(count * sizeof(FS_INFO));
-
-       for (i = 0 ; i < count ; i++) {
-               fsp = *fspp + i;
-               statfsp = lstatfsp + i;
-               lfsp = (struct lfs *)malloc (LFS_SBPAD);
-               if (get_superblock (fsp, lfsp) < 0) {
-                       perror("get_fs_info: get_superblock failed");
-                       return -1;
-               }
-               fsp->fi_daddr_shift = lfsp->lfs_bshift - lfsp->lfs_fsbtodb;
-               if (get_ifile (fsp) < 0) {
-                       perror("get_fs_info: get_ifile failed");
-                       return -1;
-               }
+       fsp = (FS_INFO *)malloc(count * sizeof(FS_INFO));
+
+       for (fp = fsp, i = 0; i < count; ++i, ++fp) {
+               fp->fi_statfsp = lstatfsp++;
+               if (get_superblock (fp, &fp->fi_lfs))
+                       err(1, "get_fs_info: get_superblock failed");
+               fp->fi_daddr_shift =
+                    fp->fi_lfs.lfs_bshift - fp->fi_lfs.lfs_fsbtodb;
+               get_ifile (fp);
        }
        }
-       return 0;
+       return (fsp);
 }
 
 }
 
-/* this is needed temporarily, because of the bug in mmap'ed files */
+/*
+ * If we are reading the ifile then we need to refresh it.  Even if
+ * we are mmapping it, it might have grown.  Finally, we need to 
+ * refresh the file system information (statfs) info.
+ */
 void
 void
-free_fs_info (fsp, count)
-       FS_INFO *fsp;   /* IN: array of fs_infos we will dispose of */
-       int     count;  /* IN: number of file systems */
+reread_fs_info(fsp, count)
+       FS_INFO *fsp;   /* IN: array of fs_infos to free */
+       int count;      /* IN: number of file systems */
 {
 {
-       int     i;
-       caddr_t fsp_base = (caddr_t)fsp;
+       int i;
        
        
-       for (i = 0 ; i < count ; i++, fsp++) {
-               /* free superblock */
-               free (lfsp);
-               /* sdp points to the beginning of the ifile area */
-#ifndef MMAP_WORKS
-               free (cip);
+       for (i = 0; i < count; ++i, ++fsp) {
+               if (statfs(fsp->fi_statfsp->f_mntonname, fsp->fi_statfsp))
+                       err(0, "reread_fs_info: statfs failed");
+#ifdef MMAP_WORKS
+               if (munmap(fsp->fi_cip, fsp->fi_ifile_length) < 0)
+                       err(0, "reread_fs_info: munmap failed");
 #else
 #else
-               if (munmap (cip, ifile_length) < 0) {
-                       perror("free_fs_info: munmap failed\n");
-               }
+               free (fsp->fi_cip);
 #endif /* MMAP_WORKS */
 #endif /* MMAP_WORKS */
+               get_ifile (fsp);
        }
        }
-       
-       free (fsp_base);
 }
 
 /* 
 }
 
 /* 
- * get_superblock: 
- *    gets the superblock from disk (possibly in face of errors) 
+ * Gets the superblock from disk (possibly in face of errors) 
  */
 int
 get_superblock (fsp, sbp)
  */
 int
 get_superblock (fsp, sbp)
-       FS_INFO *fsp;   /* IN: array of fs_infos we will dispose of */
-       struct  lfs     *sbp;
+       FS_INFO *fsp;           /* local file system info structure */
+       struct lfs *sbp;
 {
 {
-        int    fid;
-       char    mntfromname[MNAMELEN+1];
+       char mntfromname[MNAMELEN+1];
+        int fid;
 
        strcpy(mntfromname, "/dev/r");
 
        strcpy(mntfromname, "/dev/r");
-       strcat(mntfromname, statfsp->f_mntfromname+5);
+       strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
 
        if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
 
        if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
-               perror("get_superblock: bad open");
-               return -1;
+               err(0, "get_superblock: bad open");
+               return (-1);
        }
 
        }
 
-       if(lseek (fid, LFS_LABELPAD, SEEK_SET) != LFS_LABELPAD) {
-               perror("get_superblock: bad seek");
-               return -1;
-       }
-       if(read (fid, (char *)sbp, LFS_SBPAD) != LFS_SBPAD) {
-               perror("get_superblock: bad read");
-               return -1;
-       }
+       get(fid, LFS_LABELPAD, sbp, sizeof(struct lfs));
        close (fid);
        
        close (fid);
        
-       return 0;
+       return (0);
 }
 
 /* 
 }
 
 /* 
- * get_ifile: 
- *    This function will map the ifile into memory.  It returns
- * NULL on failure.
+ * This function will map the ifile into memory.  It causes a
+ * fatal error on failure.
  */
  */
-int
+void
 get_ifile (fsp)
        FS_INFO *fsp;
 {
 get_ifile (fsp)
        FS_INFO *fsp;
 {
-       int     fid;
-       int     count;
-       caddr_t ifp = NULL;
-       char    *ifile_name;
-       struct  stat file_stat;
-
-       ifile_name = (char *)
-               malloc(strlen(statfsp->f_mntonname)+strlen(IFILE_NAME)+2);
-       strcpy(ifile_name, statfsp->f_mntonname);
-       strcat(ifile_name, "/");
-       strcat(ifile_name, IFILE_NAME);
-
-       if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0) {
-               perror("get_ifile: bad open");
-               return -1;
-       }
+       struct stat file_stat;
+       caddr_t ifp;
+       char *ifile_name;
+       int count, fid;
 
 
-       if(fstat (fid, &file_stat)) {
-               perror("get_ifile: fstat failed");
-               return -1;
-       }
-       ifile_length = file_stat.st_size;
+       ifp = NULL;
+       sync();
+       ifile_name = malloc(strlen(fsp->fi_statfsp->f_mntonname) +
+           strlen(IFILE_NAME)+2);
+       strcat(strcat(strcpy(ifile_name, fsp->fi_statfsp->f_mntonname), "/"),
+           IFILE_NAME);
+
+       if ((fid = open(ifile_name, O_RDWR, (mode_t)0)) < 0)
+               err(1, "get_ifile: bad open");
+
+       if (fstat (fid, &file_stat))
+               err(1, "get_ifile: fstat failed");
+
+       fsp->fi_ifile_length = file_stat.st_size;
 
        /* get the ifile */
 #ifndef MMAP_WORKS
 
        /* get the ifile */
 #ifndef MMAP_WORKS
-       ifp = (caddr_t)malloc (ifile_length);
-       if (ifp == 0) {
-               perror ("get_ifile: malloc failed, out of memory?"); 
-               return -1;
-       }
-       count = read (fid, ifp, ifile_length);
-
-       if (count != ifile_length) {
-               perror("get_ifile: bad ifile read"); 
-               return -1;
+       if (!(ifp = malloc ((size_t)fsp->fi_ifile_length)))
+               err (1, "get_ifile: malloc failed"); 
+redo_read:
+       count = read (fid, ifp, (size_t) fsp->fi_ifile_length);
+
+       if (count < 0)
+               err(1, "get_ifile: bad ifile read"); 
+       else if (count < (int)fsp->fi_ifile_length) {
+               err(0, "get_ifile");
+               if (lseek(fid, 0, SEEK_SET) < 0)
+                       err(1, "get_ifile: bad ifile lseek"); 
+               goto redo_read;
        }
 #else  /* MMAP_WORKS */
        }
 #else  /* MMAP_WORKS */
-       ifp = mmap ((caddr_t)0, ifile_length, PROT_READ|PROT_WRITE,
+       ifp = mmap ((caddr_t)0, (size_t) fsp->fi_ifile_length, PROT_READ|PROT_WRITE,
                MAP_FILE|MAP_SHARED, fid, (off_t)0);
                MAP_FILE|MAP_SHARED, fid, (off_t)0);
-       if (ifp < 0) {
-               perror("get_ifile: mmap failed");
-               return NULL;
-       }
+       if (ifp < 0)
+               err(1, "get_ifile: mmap failed");
 #endif /* MMAP_WORKS */
 
        close (fid);
 
 #endif /* MMAP_WORKS */
 
        close (fid);
 
-       cip = (CLEANERINFO*)ifp;
-       segusep = (SEGUSE*)(ifp + CLEANSIZE(lfsp));
-       ifilep  = (IFILE*)(ifp + CLEANSIZE(lfsp) + SEGTABSIZE(lfsp));
-       /* # of bytes in ifile table */
-       ifile_count = ifile_length - (CLEANSIZE(lfsp) + SEGTABSIZE(lfsp));
-       /* # of ifile entries in ifile table */
-       ifile_count = (ifile_count / lfsp->lfs_bsize) * lfsp->lfs_ifpb;
+       fsp->fi_cip = (CLEANERINFO *)ifp;
+       fsp->fi_segusep = (SEGUSE *)(ifp + CLEANSIZE(fsp));
+       fsp->fi_ifilep  = (IFILE *)((caddr_t)fsp->fi_segusep + SEGTABSIZE(fsp));
+
+       /*
+        * The number of ifile entries is equal to the number of blocks
+        * blocks in the ifile minus the ones allocated to cleaner info
+        * and segment usage table multiplied by the number of ifile
+        * entries per page.
+        */
+       fsp->fi_ifile_count = (fsp->fi_ifile_length >> fsp->fi_lfs.lfs_bshift -
+           fsp->fi_lfs.lfs_cleansz - fsp->fi_lfs.lfs_segtabsz) *
+           fsp->fi_lfs.lfs_ifpb;
+
        free (ifile_name);
        free (ifile_name);
-       return 0;
 }
 
 }
 
-
 /*
 /*
- * segmapv:
- *
- *   This function will scan a segment and return a list of
+ * This function will scan a segment and return a list of
  * <inode, blocknum> pairs which indicate which blocks were
  * <inode, blocknum> pairs which indicate which blocks were
- * contained as live data within the segment at some point
- * (it may have "died" since then).  Any given pair will be 
- * listed at most once.
+ * contained as live data within the segment when the segment
+ * summary was read (it may have "died" since then).  Any given
+ * pair will be listed at most once.
  */
 int 
 lfs_segmapv(fsp, seg, seg_buf, blocks, bcount, inodes, icount)
  */
 int 
 lfs_segmapv(fsp, seg, seg_buf, blocks, bcount, inodes, icount)
-       FS_INFO *fsp;           /* pointer to super block */
-       int     seg;            /* the segment id */
-       caddr_t seg_buf;        /* the buffer containing the segment's data */
-                               /* OUT: array of block_info for live blocks */
-       BLOCK_INFO      **blocks;
-       int     *bcount;        /* OUT: number of active blocks in segment */
-                               /* OUT: array of inode_info for live inodes */
-       INODE_INFO      **inodes;
-       int     *icount;        /* OUT: number of active inodes in segment */
+       FS_INFO *fsp;           /* pointer to local file system information */
+       int seg;                /* the segment number */
+       caddr_t seg_buf;        /* the buffer containing the segment's data */
+       BLOCK_INFO **blocks;    /* OUT: array of block_info for live blocks */
+       int *bcount;            /* OUT: number of active blocks in segment */
+       INODE_INFO **inodes;    /* OUT: array of inode_info for live inodes */
+       int *icount;            /* OUT: number of active inodes in segment */
 {
 {
-       caddr_t s;
-       caddr_t endofseg;
-       int     nextsum;
-       u_long  sb_off;
-       time_t  timestamp;
-       
+       BLOCK_INFO *bip;
+       INODE_INFO *iip;
+       SEGSUM *sp;
+       SEGUSE *sup;
+       struct lfs *lfsp;
+       caddr_t s, segend;
+       daddr_t pseg_addr, seg_addr;
+       int nblocks, num_iblocks;
+       time_t timestamp;
+
+       lfsp = &fsp->fi_lfs;
+       num_iblocks = lfsp->lfs_ssize;
+       if (!(bip = malloc(lfsp->lfs_ssize * sizeof(BLOCK_INFO))))
+               goto err0;
+       if (!(iip = malloc(lfsp->lfs_ssize * sizeof(INODE_INFO))))
+               goto err1;
+
+       sup = SEGUSE_ENTRY(lfsp, fsp->fi_segusep, seg);
+       s = seg_buf + (sup->su_flags & SEGUSE_SUPERBLOCK ? LFS_SBPAD : 0);
+       seg_addr = sntoda(lfsp, seg);
+       pseg_addr = seg_addr + (sup->su_flags & SEGUSE_SUPERBLOCK ? btodb(LFS_SBPAD) : 0);
+#ifdef VERBOSE
+               printf("\tsegment buffer at: 0x%x\tseg_addr 0x%x\n", s, seg_addr);
+#endif /* VERBOSE */
+
        *bcount = 0;
        *bcount = 0;
-       *blocks = (BLOCK_INFO *)malloc (sizeof(BLOCK_INFO));
-       
        *icount = 0;
        *icount = 0;
-       *inodes = (INODE_INFO *)malloc(sizeof(INODE_INFO));
-
-       sb_off = (SEGUSE_ENTRY(lfsp, segusep, seg)->su_flags & SEGUSE_SUPERBLOCK) ?
-               LFS_SBPAD : 0;
-
-       for (s = seg_buf + sb_off, endofseg = seg_buf + seg_size(lfsp), 
-            timestamp = 0 ; 
-            s < endofseg ; 
-            s += pseg_size (fsp, (SEGSUM*)s)) {
-               BLOCK_INFO      *pblocks;
-               int             pbcount;
-               INODE_INFO      *pinodes;
-               int             picount;
-
+       for (segend = seg_buf + seg_size(lfsp), timestamp = 0; s < segend; ) {
+               sp = (SEGSUM *)s;
 #ifdef VERBOSE
 #ifdef VERBOSE
-               printf("lfs_segmapv: seg_buf = 0x%x, pseg_buf = 0x%x, offset = %lu (0x%x), pseg = \n\t",
-                       (u_int)seg_buf, (u_int)s, 
-                       (u_int)s - (u_int)seg_buf - (u_int)sb_off,
-                       (u_int)s - (u_int)seg_buf - (u_int)sb_off);
-/* this can cause core dumps when printing an invalid segsum
- *             print_SEGSUM ((SEGSUM*)s);
- *             printf("\n");
- *             printf("pseg_size = %lu\n", pseg_size(fsp, (SEGSUM*)s));
- */
+               printf("\tpartial at: 0x%x\n", pseg_addr);
+               print_SEGSUM(lfsp, sp);
                fflush(stdout);
 #endif /* VERBOSE */
 
                fflush(stdout);
 #endif /* VERBOSE */
 
-               /* we have hit the end of the valid data */
-               if (! pseg_valid (fsp, (SEGSUM*)s)) break;
-
-               /* we have gone back in time and hit old data */
-               if (timestamp > ((SEGSUM*)s)->ss_create) break;
+               nblocks = pseg_valid(fsp, sp);
+               if (nblocks <= 0)
+                       break;
 
 
+               /* Check if we have hit old data */
+               if (timestamp > ((SEGSUM*)s)->ss_create)
+                       break;
                timestamp = ((SEGSUM*)s)->ss_create;
 
                timestamp = ((SEGSUM*)s)->ss_create;
 
-               /* get the block and inode list */
-               pseg_blocks (fsp, seg, (SEGSUM*)s, seg_buf, 
-                       &pblocks, &pbcount);
-               pseg_bjoin  (fsp, blocks, bcount, pblocks, pbcount);
-
-               pseg_inodes (fsp, seg, (SEGSUM*)s, seg_buf, 
-                       &pinodes, &picount);
-               pseg_ijoin  (fsp, inodes, icount, pinodes, picount);
-               
-               /* free the temporary tables */
-               free (pblocks);
-               free (pinodes);
+               /*
+                * Right now we die if we run out of room, we could probably
+                * recover if we were smart.
+                */
+               if (*icount + sp->ss_ninos > num_iblocks) {
+                       num_iblocks = *icount + sp->ss_ninos;
+                       iip = realloc (iip, num_iblocks * sizeof(INODE_INFO));
+                       if (!iip)
+                               goto err1;
+               }
+               add_inodes(fsp, iip, icount, sp, seg_buf, seg_addr);
+               add_blocks(fsp, bip, bcount, sp, seg_buf, seg_addr, pseg_addr);
+               pseg_addr += fsbtodb(lfsp, nblocks) +
+                   bytetoda(fsp, LFS_SUMMARY_SIZE);
+               s += (nblocks << lfsp->lfs_bshift) + LFS_SUMMARY_SIZE;
        }
        }
+       qsort(iip, *icount, sizeof(INODE_INFO), ii_compare);
+       qsort(bip, *bcount, sizeof(BLOCK_INFO), bi_compare);
+       toss(iip, icount, sizeof(INODE_INFO), ii_toss, NULL);
+       toss(bip, bcount, sizeof(BLOCK_INFO), bi_toss, NULL);
+#ifdef VERBOSE
+       {
+               BLOCK_INFO *_bip;
+               INODE_INFO *_iip;
+               int i;
+
+               printf("BLOCK INFOS\n");
+               for (_bip = bip, i=0; i < *bcount; ++_bip, ++i)
+                       PRINT_BINFO(_bip);
+               printf("INODE INFOS\n");
+               for (_iip = iip, i=0; i < *icount; ++_iip, ++i)
+                       PRINT_IINFO(1, _iip);
+       }
+#endif
+       *blocks = bip;
+       *inodes = iip;
+       return (0);
+
+err1:  free(bip);
+err0:  *bcount = 0;
+       *icount = 0;
+       return (-1);
        
 }
 
 /* 
        
 }
 
 /* 
- * this will parse a partial segment and create a vector of block_info's
- * for live data and a vector of inode_info's for live inodes.  It will 
- * not include blocks or inodes from files with new version numbers.  
+ * This will parse a partial segment and fill in BLOCK_INFO structures
+ * for each block described in the segment summary.  It will not include
+ * blocks or inodes from files with new version numbers.  
  */
 void
  */
 void
-pseg_blocks (fsp, seg, s, seg_buf, blocks, count)
+add_blocks (fsp, bip, countp, sp, seg_buf, segaddr, psegaddr)
        FS_INFO *fsp;           /* pointer to super block */
        FS_INFO *fsp;           /* pointer to super block */
-       int     seg;            /* the segment id */
-       SEGSUM  *s;             /* (unvalidated) segsum pointer */
-       caddr_t seg_buf;        /* the buffer containing the segment's data */
-                               /* OUT: array of block_info for live blocks */
-       BLOCK_INFO      **blocks;
-       int     *count;         /* OUT: number of active blocks in segment */
+       BLOCK_INFO *bip;        /* Block info array */
+       int *countp;            /* IN/OUT: number of blocks in array */
+       SEGSUM  *sp;            /* segment summmary pointer */
+       caddr_t seg_buf;        /* buffer containing segment */
+       daddr_t segaddr;        /* address of this segment */
+       daddr_t psegaddr;       /* address of this partial segment */
 {
 {
-       FINFO   **finfos;
-       int     finfoc;
-       int     blockc;
-       int     i;
-       int     j;
-       int     ninob;          /* number of inode blocks passed */
-       daddr_t seg_daddr;
-       daddr_t *cur_iaddrp;    /* pointer to current inode block */
-       u_long  offset;         /* the offset (in bytes) within the segment */
-
-       *count = 0;
-       *blocks = NULL;
-       
-       pseg_finfos (fsp, s, &finfos, &finfoc);
+       IFILE   *ifp;
+       FINFO   *fip;
+       caddr_t bp;
+       daddr_t *dp;
+       daddr_t *iaddrp;        /* pointer to current inode block */
+       int db_per_block, i, j;
+       u_long page_size;
 
 #ifdef VERBOSE
 
 #ifdef VERBOSE
-       for(i=0;i<finfoc;i++){print_FINFO(finfos[i]);printf("\n");fflush(stdout);}
-       printf("pseg_blocks: finfoc = %d\n", finfoc);fflush(stdout);
+       printf("FILE INFOS\n");
 #endif
 #endif
-
-       /* count how many blocks are held by live FINFO's */
-       for (i = 0, blockc = 0 ; i < finfoc ; ++i)
-               if (finfos[i]->fi_version == 
-                   IFILE_ENTRY(lfsp, ifilep, finfos[i]->fi_ino)->if_version) 
-                       blockc += finfos[i]->fi_nblocks;
-
-       if (finfoc == 0 || blockc == 0) return;
-       
-       ninob = 0;
-       offset = LFS_SUMMARY_SIZE + ((u_int)s - (u_int)seg_buf) + 
-               s->ss_next * datobyte(fsp, 1<<lfsp->lfs_bshift);
-       cur_iaddrp = (daddr_t*)(s->ss_ninos == 0 ? 0 :
-           (char *)s + LFS_SUMMARY_SIZE - sizeof(daddr_t));
-       seg_daddr = sntoda(lfsp, seg);
-       *blocks = (BLOCK_INFO *)malloc (blockc*sizeof(BLOCK_INFO));
-
-       for (i = 0 ; i < finfoc ; i ++) {
-               FINFO           *f = finfos[i];
-
-               if (f->fi_version != IFILE_ENTRY(lfsp, ifilep, f->fi_ino)->if_version) 
+       db_per_block = fsbtodb(&fsp->fi_lfs, 1);
+       page_size = fsp->fi_lfs.lfs_bsize;
+       bp = seg_buf + datobyte(fsp, psegaddr - segaddr) + LFS_SUMMARY_SIZE;
+       bip += *countp;
+       psegaddr += bytetoda(fsp, LFS_SUMMARY_SIZE);
+       iaddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
+       --iaddrp;
+       for (fip = (FINFO *)(sp + 1), i = 0; i < sp->ss_nfinfo;
+           ++i, fip = (FINFO *)(&fip->fi_blocks[fip->fi_nblocks])) {
+
+               ifp = IFILE_ENTRY(&fsp->fi_lfs, fsp->fi_ifilep, fip->fi_ino);
+               PRINT_FINFO(fip, ifp);
+               if (ifp->if_version > fip->fi_version)
                        continue;
                        continue;
-
-#ifdef VERBOSE
-               printf("finfo %d = ", i);
-               print_FINFO(f);
-               printf("\n");
-               fflush(stdout);
-               printf("IFILE entry for file %d = ", f->fi_ino);
-               print_IFILE (IFILE_ENTRY(lfsp, ifilep, f->fi_ino));
-               printf("\n");
-               fflush(stdout);
-#endif
-               for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++) {
-                       BLOCK_INFO      *b = &(*blocks)[*count];
-               
-                       /*
-                        * XXX: 
-                        * this changes if we have variable size blocks
-                        */
-                       for (;cur_iaddrp && 
-                           seg_daddr + bytetoda(fsp, offset) == *cur_iaddrp; 
-                           offset += datobyte(fsp, 1<<lfsp->lfs_bshift)) {
-                               if (ninob <= (s->ss_ninos + INOPB(lfsp) - 1) 
-                                   / INOPB(lfsp)) {
-                                       ++ninob;
-                                       --cur_iaddrp;
-                               } else
-                                       cur_iaddrp = NULL;
+               dp = &(fip->fi_blocks[0]);
+               for (j = 0; j < fip->fi_nblocks; j++, dp++) {
+                       while (psegaddr == *iaddrp) {
+                               psegaddr += db_per_block;
+                               bp += page_size;
+                               --iaddrp;
                        }
                        }
-                       b->bi_inode = f->fi_ino;
-                       b->bi_lbn = f->fi_blocks[j];
-                       b->bi_daddr = seg_daddr + bytetoda(fsp, offset);
-                       b->bi_segcreate = s->ss_create;
-                       b->bi_bp = seg_buf + offset;
-                       
-                       (*count) ++;
-                       offset += blocksize(fsp, b->bi_lbn);
-#ifdef VERBOSE
-                       printf("\tb[%d] = ", j);
-                       print_BLOCK_INFO(b);
-                       printf("\n");
-                       fflush(stdout);
-#endif
+                       bip->bi_inode = fip->fi_ino;
+                       bip->bi_lbn = *dp;
+                       bip->bi_daddr = psegaddr;
+                       bip->bi_segcreate = (time_t)(sp->ss_create);
+                       bip->bi_bp = bp;
+                       psegaddr += db_per_block;
+                       bp += page_size;
+                       ++bip;
+                       ++(*countp);
                }
        }
                }
        }
-       free (finfos);
 }
 
 }
 
+/*
+ * For a particular segment summary, reads the inode blocks and adds
+ * INODE_INFO structures to the array.  Returns the number of inodes
+ * actually added.
+ */
 void
 void
-pseg_inodes (fsp, seg, s, seg_buf, inodes, count)
+add_inodes (fsp, iip, countp, sp, seg_buf, seg_addr)
        FS_INFO *fsp;           /* pointer to super block */
        FS_INFO *fsp;           /* pointer to super block */
-       int     seg;            /* the segment id */
-       SEGSUM  *s;             /* (unvalidated) segsum pointer */
+       INODE_INFO *iip;
+       int *countp;            /* pointer to current number of inodes */
+       SEGSUM *sp;             /* segsum pointer */
        caddr_t seg_buf;        /* the buffer containing the segment's data */
        caddr_t seg_buf;        /* the buffer containing the segment's data */
-                               /* OUT: array of inode_info for live inodes */
-       INODE_INFO      **inodes;
-       int     *count;         /* OUT: number of active inodes in segment */
+       daddr_t seg_addr;       /* disk address of seg_buf */
 {
 {
-       int     i;
-       ino_t   inum;
-       daddr_t *daddrp, i_daddr, seg_daddr;
-       struct  dinode  *di;
+       struct dinode *di;
+       struct lfs *lfsp;
+       IFILE *ifp;
+       INODE_INFO *ip;
+       daddr_t *daddrp;
+       ino_t inum;
+       int i;
        
        
-       *count = 0;
-       *inodes = NULL;
-
-       if (s->ss_ninos <= 0) return;
+       if (sp->ss_ninos <= 0)
+               return;
        
        
-       *inodes = (INODE_INFO *)malloc (s->ss_ninos * sizeof(INODE_INFO));
-
-       seg_daddr = sntoda(lfsp, seg);
-
+       ip = iip + *countp;
+       lfsp = &fsp->fi_lfs;
 #ifdef VERBOSE
 #ifdef VERBOSE
-       printf("pseg_inodes:\n");
-       print_SEGSUM(s);
-       printf("\n");
-       fflush(stdout);
+       (void) printf("INODE_INFOS:\n");
 #endif
 #endif
-
-       daddrp = (daddr_t *)((caddr_t)s + LFS_SUMMARY_SIZE);
-
-       for (i = 0 ; i < s->ss_ninos ; ++i) {
-
+       daddrp = (daddr_t *)((caddr_t)sp + LFS_SUMMARY_SIZE);
+       for (i = 0; i < sp->ss_ninos; ++i) {
                if (i % INOPB(lfsp) == 0) {
                if (i % INOPB(lfsp) == 0) {
-                       i_daddr = *--daddrp;
-                       if (datosn(lfsp, i_daddr) != seg ||
-                           datobyte(fsp, i_daddr - seg_daddr) > seg_size(lfsp)) {
-                               printf("pseg_inodes: bad i_daddr\n");
-                               print_SEGSUM(s);
-                               printf("\n");
-                               fflush(stdout);
-                               printf("i_daddr = %d, seg_daddr = %d, offset = %d, pseg_size = %d\n",
-                                   i_daddr, seg_daddr, i_daddr - seg_daddr, 
-                                   pseg_size(fsp, (SEGSUM*)s));
-                               fflush(stdout);
-                       }
-                       di = (struct dinode *)
-                               (seg_buf + datobyte(fsp, i_daddr - seg_daddr));
+                       --daddrp;
+                       di = (struct dinode *)(seg_buf +
+                           ((*daddrp - seg_addr) << fsp->fi_daddr_shift));
                } else 
                        ++di;
                
                inum = di->di_inum;
                } else 
                        ++di;
                
                inum = di->di_inum;
-
-               if (IFILE_ENTRY(lfsp, ifilep, inum)->if_daddr == i_daddr) {
-                       (*inodes)[*count].ii_inode = inum;
-                       (*inodes)[*count].ii_daddr = i_daddr;
-                       (*inodes)[*count].ii_segcreate = s->ss_create;
-                       (*inodes)[*count].ii_dinode = di;
-               
-                       (*count) ++;
+               ip->ii_daddr = *daddrp;
+               ip->ii_inode = inum;
+               ip->ii_dinode = di;
+               ip->ii_segcreate = sp->ss_create;
+
+               ifp = IFILE_ENTRY(lfsp, fsp->fi_ifilep, inum);
+               PRINT_IINFO(ifp->if_daddr == *daddrp, ip);
+               if (ifp->if_daddr == *daddrp) {
+                       ip++;
+                       ++(*countp);
                } 
        }
 }
 
                } 
        }
 }
 
-/* return the size of the partial segment in bytes. */
-u_long
-pseg_size (fsp, s)
-       FS_INFO *fsp;   /* pointer to super block */
-       SEGSUM  *s;     /* segsum pointer */
-{
-       int     i;
-       int     j;
-       FINFO   **finfos;
-       int     finfoc;
-       u_long  size = LFS_SUMMARY_SIZE;
-       
-       pseg_finfos (fsp, s, &finfos, &finfoc);
-       for (i = 0 ; i < finfoc ; i ++) 
-       for (j = 0 ; j < finfos[i]->fi_nblocks ; j ++) 
-               size += blocksize(fsp, finfos[i]->fi_blocks[j]);
-
-       /* inodes are packed INOPB inodes per block */
-       /* there can be unused space in an inode block */
-       size += datobyte(fsp, fsbtodb(lfsp,1)*((s->ss_ninos+INOPB(lfsp)-1)/INOPB(lfsp)));
-
-       return size;
-}
-
-/* 
- * join block list b with list a (eliminating duplicates), leaving result
- * in list a.
- */
-void
-pseg_bjoin (fsp, ablocks, acount, bblocks, bcount)
-       FS_INFO *fsp;   /* pointer to file system info */
-                               /* INOUT: array of live blocks block_info */
-       BLOCK_INFO      **ablocks;
-       int     *acount;        /* INOUT: number of active blocks */
-                               /* IN: array of live blocks block_info */
-       BLOCK_INFO      *bblocks;
-       int     bcount; /* IN: number of active blocks */
-{
-       int     i;
-       int     j;
-       BLOCK_INFO      *abp;
-       BLOCK_INFO      *bbp;
-
-#ifdef VERBOSE
-       printf("pseg_bjoin: *acount = %d, bcount = %d\n", *acount, bcount);
-/**/
-       printf("ablocks = \n");
-       for(i=0;i<*acount;i++){print_BLOCK_INFO((*ablocks)+i); printf("\n");}
-/**/
-       printf("bblocks = \n");
-       for(i=0;i<bcount;i++){print_BLOCK_INFO(bblocks+i); printf("\n");}
-/**/
-       fflush(stdout);
-/**/
-#endif
-
-       for (i = 0, bbp = bblocks ; i < bcount ; ++i, ++bbp) {
-               for (j = 0, abp = *ablocks ; j < *acount ; ++j, ++abp) {
-                       if (abp->bi_inode == bbp->bi_inode
-                               && abp->bi_lbn == bbp->bi_lbn) {
-                               /* the data is for the same file and logical block */
-                               if (abp->bi_segcreate < bbp->bi_segcreate)
-                                       *abp = *bbp;
-                               break;
-                       }
-               }
-               if (j == *acount) {
-                       /* this is a block we haven't seen before */
-                       *ablocks = (BLOCK_INFO*)
-                               realloc (*ablocks, sizeof(BLOCK_INFO)*(*acount + 1));
-                       (*ablocks)[*acount] = *bbp;
-                       (*acount) ++;
-               }
-       }
-}
-
-/* 
- * join block list b with list a (eliminating duplicates), leaving result
- * in list a.
- */
-void
-pseg_ijoin (fsp, ainodes, acount, binodes, bcount)
-       FS_INFO *fsp;   /* pointer to file system info */
-                               /* INOUT: array of live inodes inode_info */
-       INODE_INFO      **ainodes;
-       int     *acount;        /* INOUT: number of active inodes */
-                               /* IN: array of live inodes inode_info */
-       INODE_INFO      *binodes;
-       int     bcount;         /* IN: number of active inodes */
-{
-       int     i;
-       int     j;
-       daddr_t daddr;
-       INODE_INFO      *aip;
-       INODE_INFO      *bip;
-
-       /* we assume that we have no duplicate live inodes on "a" and "b" */
-       
-       /* eliminate dead inodes from "a" */
-       for (i = 0, aip = *ainodes ; i < *acount ; ++aip ) {
-               daddr = IFILE_ENTRY(lfsp, ifilep, aip->ii_inode)->if_daddr;
-               if (daddr != aip->ii_daddr) 
-                       *aip = (*ainodes)[--(*acount)];
-               else    i++;
-       }
-
-       /* eliminate dead inodes from "b" */
-       for (i = 0, bip = binodes ; i < bcount ; ++bip) {
-               daddr = IFILE_ENTRY(lfsp, ifilep, bip->ii_inode)->if_daddr;
-               if (daddr != bip->ii_daddr) {
-                       /* don't really need to do this, only we don't want
-                          to lose any inodes, just in case */
-                       INODE_INFO      tmp;
-                       tmp = *bip;
-                       *bip = binodes[bcount];
-                       binodes[bcount] = tmp;
-                       bcount --;
-               }
-               else    i++;
-       }
-       /* append "b" to "a" */
-       if (bcount > 0) {
-               *ainodes = (INODE_INFO *)realloc ((void *)*ainodes,
-                       (*acount + bcount + 1)*sizeof(INODE_INFO));
-               for (i = 0 ; i < bcount ; i ++)
-                       (*ainodes)[(*acount)++] = binodes[i];
-       }
-}
-
-/* is the segsum block valid? return TRUE if it is, FALSE otherwise */
-int 
-segsum_valid (fsp, ssp)
-       FS_INFO *fsp;   /* pointer to file system info */
-       SEGSUM  *ssp;   /* pointer to segment summary block */
-{
-       u_long  sumsum;
-
-       /* check segsum block checksum */
-       sumsum = cksum(&ssp->ss_datasum, 
-           LFS_SUMMARY_SIZE - sizeof(ssp->ss_sumsum));
-
-       if (sumsum != ssp->ss_sumsum) return FALSE;
-       
-       return TRUE;
-}
-
 /*
 /*
- * pseg_valid:
- *
- * returns 1 if the partial segment is valid, and 0 if it is invalid.
- * it uses the checksums to verify validity.
+ * Checks the summary checksum and the data checksum to determine if the
+ * segment is valid or not.  Returns the size of the partial segment if it
+ * is valid, * and 0 otherwise.  Use dump_summary to figure out size of the
+ * the partial as well as whether or not the checksum is valid.
  */     
 int
 pseg_valid (fsp, ssp)
        FS_INFO *fsp;   /* pointer to file system info */
  */     
 int
 pseg_valid (fsp, ssp)
        FS_INFO *fsp;   /* pointer to file system info */
-       SEGSUM  *ssp;   /* pointer to segment summary block */
+       SEGSUM *ssp;    /* pointer to segment summary block */
 {
 {
-       u_long  datasum;
-       u_long  size;
-       int     nblocks;
-       int     i;
-       u_long  *datap;
        caddr_t p;
        caddr_t p;
+       int i, nblocks;
+       u_long *datap;
 
 
-       /* check segsum block checksum */
-       if (segsum_valid (fsp, ssp) == FALSE) return FALSE;
-
-       return TRUE;
+       if ((nblocks = dump_summary(&fsp->fi_lfs, ssp, 0, NULL)) <= 0)
+               return(0);
                
                
-       /* check data/inode block(s) checksum too... */
-       size = pseg_size (fsp, ssp);
-       nblocks = size/fsbtodb(lfsp, 1);
-       datap = (u_long*)malloc(sizeof(u_long)*nblocks);
+       /* check data/inode block(s) checksum too */
+       datap = (u_long *)malloc(nblocks * sizeof(u_long));
        p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
        p = (caddr_t)ssp + LFS_SUMMARY_SIZE;
-       for (i = 0 ; i < nblocks ; i ++) {
+       for (i = 0; i < nblocks; ++i) {
                datap[i] = *((u_long *)p);
                datap[i] = *((u_long *)p);
-               p += lfsp->lfs_bsize;
+               p += fsp->fi_lfs.lfs_bsize;
        }
        }
-       datasum = cksum ((void *)datap, nblocks*sizeof(u_long));
-       if (datasum != ssp->ss_datasum) return FALSE;
+       if (cksum ((void *)datap, nblocks * sizeof(u_long)) != ssp->ss_datasum)
+               return (0);
        
        
-       return TRUE;
+       return (nblocks);
 }
 
 }
 
-/* get array of FINFO pointers for partial segment */
-void
-pseg_finfos (fsp, ssp, finfos, count)
-       FS_INFO *fsp;   /* pointer to file system info */
-       SEGSUM  *ssp;   /* pointer to segment summary block */
-       FINFO   ***finfos;      /* OUT: return an array of FINFO pointers */
-       int     *count;         /* OUT: return size of array */
-{
-       caddr_t p = (caddr_t)ssp + sizeof(SEGSUM);
-       int     i;
-       FINFO   *fip;
-       
-       *count = 0;
-       *finfos = NULL;
-
-       if (ssp->ss_nfinfo > 0)
-               *finfos = (FINFO**)malloc (ssp->ss_nfinfo*sizeof(FINFO*));
-
-       for (i = 0 ; i < ssp->ss_nfinfo ; i ++) {
-               fip = (FINFO *)p;
-               (*finfos)[*count] = fip;
-               (*count) ++;
-               p += finfo_size (fip);
-       }
-}
-
-/*
- * blocksize:
- *
- * returns the size (in bytes) of a (logical) block.
- * this is used because lfs uses different block sizes, depending
- * on the logical # of the block.  Lfs uses various sizes so
- * it doesn't need fragments.
- */ 
-u_long
-blocksize (fsp, index)
-       FS_INFO *fsp;   /* pointer to file system info */
-       int     index;  /* logical block # w/in file */
-{
-       return lfsp->lfs_bsize; /* XXX: blocksize might depend on
-                                       the logical block number */
-}
-
-/*
- * finfo_size
- *
- * returns the size in bytes of an FINFO structure 
- */
-u_long
-finfo_size (finfop)
-       FINFO   *finfop;
-{
-       return sizeof(FINFO) + sizeof(long)*(finfop->fi_nblocks-1);
-}
-       
 
 /* #define MMAP_SEGMENT */
 /* 
  * read a segment into a memory buffer
  */
 int
 
 /* #define MMAP_SEGMENT */
 /* 
  * read a segment into a memory buffer
  */
 int
-mmap_segment (fsp, segment, seg_buf)
-       FS_INFO *fsp;           /* file system information */
-       int     segment;        /* the index of the segment to be cleaned */
-       caddr_t *seg_buf;       /* pointer to buffer area */
+mmap_segment (fsp, segment, segbuf)
+       FS_INFO *fsp;           /* file system information */
+       int segment;            /* segment number */
+       caddr_t *segbuf;        /* pointer to buffer area */
 {
 {
-       off_t   seg_daddr;      /* base disk address of segment */
-       int     fid;            /* fildes for file system device */
-       char    mntfromname[MNAMELEN+2];
+       struct lfs *lfsp;
+       int fid;                /* fildes for file system device */
+       daddr_t seg_daddr;      /* base disk address of segment */
+       off_t seg_byte;
+       size_t ssize;
+       char mntfromname[MNAMELEN+2];
+
+       lfsp = &fsp->fi_lfs;
 
        /* get the disk address of the beginning of the segment */
        seg_daddr = sntoda(lfsp, segment);
 
        /* get the disk address of the beginning of the segment */
        seg_daddr = sntoda(lfsp, segment);
+       seg_byte = datobyte(fsp, seg_daddr);
+       ssize = seg_size(lfsp);
 
        strcpy(mntfromname, "/dev/r");
 
        strcpy(mntfromname, "/dev/r");
-       strcat(mntfromname, statfsp->f_mntfromname+5);
+       strcat(mntfromname, fsp->fi_statfsp->f_mntfromname+5);
 
        if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
 
        if ((fid = open(mntfromname, O_RDONLY, (mode_t)0)) < 0) {
-               perror("mmap_segment: bad open");
-               return -1;
+               err(0, "mmap_segment: bad open");
+               return (-1);
        }
 
 #ifdef MMAP_SEGMENT
        }
 
 #ifdef MMAP_SEGMENT
-       *seg_buf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
-               MAP_FILE, fid, (off_t)datobyte(fsp, seg_daddr));
-       if ((long)*seg_buf < 0) {
-               perror("mmap_segment: mmap failed");
-               return NULL;
+       *segbuf = mmap ((caddr_t)0, seg_size(lfsp), PROT_READ,
+           MAP_FILE, fid, seg_byte);
+       if (*(long *)segbuf < 0) {
+               err(0, "mmap_segment: mmap failed");
+               return (NULL);
        }
 #else /* MMAP_SEGMENT */
        }
 #else /* MMAP_SEGMENT */
-       printf("mmap_segment: seg_daddr = %lu, seg_size = %lu, seg_offset = %lu\n", 
-               seg_daddr, seg_size(lfsp), datobyte(fsp, seg_daddr));
+#ifdef VERBOSE
+       printf("mmap_segment\tseg_daddr: %lu\tseg_size: %lu\tseg_offset: %qu\n",
+           seg_daddr, ssize, seg_byte);
+#endif
        /* malloc the space for the buffer */
        /* malloc the space for the buffer */
-       *seg_buf = (caddr_t)malloc(seg_size(lfsp));
+       *segbuf = malloc(ssize);
+       if (!*segbuf) {
+               err(0, "mmap_segment: malloc failed");
+               return(NULL);
+       }
 
        /* read the segment data into the buffer */
 
        /* read the segment data into the buffer */
-       if (datobyte(fsp, seg_daddr) != lseek (fid, datobyte(fsp, seg_daddr), SEEK_SET)) {
-               perror ("mmap_segment: bad lseek");
-               return -1;
+       if (lseek (fid, seg_byte, SEEK_SET) != seg_byte) {
+               err (0, "mmap_segment: bad lseek");
+               free(*segbuf);
+               return (-1);
        }
        
        }
        
-       if (seg_size(lfsp) != read (fid, *seg_buf, seg_size(lfsp))) {
-               perror ("mmap_segment: bad read");
-               return -1;
+       if (read (fid, *segbuf, ssize) != ssize) {
+               err (0, "mmap_segment: bad read");
+               free(*segbuf);
+               return (-1);
        }
 #endif /* MMAP_SEGMENT */
        close (fid);
 
        }
 #endif /* MMAP_SEGMENT */
        close (fid);
 
-       return 0;
+       return (0);
 }
 
 void
 munmap_segment (fsp, seg_buf)
 }
 
 void
 munmap_segment (fsp, seg_buf)
-       FS_INFO *fsp;           /* file system information */
-       caddr_t seg_buf;        /* pointer to buffer area */
+       FS_INFO *fsp;           /* file system information */
+       caddr_t seg_buf;        /* pointer to buffer area */
 {
 #ifdef MMAP_SEGMENT
 {
 #ifdef MMAP_SEGMENT
-       munmap (seg_buf, seg_size(lfsp));
+       munmap (seg_buf, seg_size(&fsp->fi_lfs));
 #else /* MMAP_SEGMENT */
        free (seg_buf);
 #endif /* MMAP_SEGMENT */
 #else /* MMAP_SEGMENT */
        free (seg_buf);
 #endif /* MMAP_SEGMENT */
@@ -778,187 +544,115 @@ munmap_segment (fsp, seg_buf)
 /*
  * USEFUL DEBUGGING TOOLS:
  */
 /*
  * USEFUL DEBUGGING TOOLS:
  */
-
 void
 void
-print_IFILE (p)
-       IFILE   *p;
+print_SEGSUM (lfsp, p)
+       struct lfs *lfsp;
+       SEGSUM  *p;
 {
 {
-       if (p) {
-               if (p->if_daddr == 0) 
-                       printf("{free, if_version=%lu, if_nextfree=%lu}",
-                               p->if_version, p->if_nextfree);
-               else
-                       printf("{if_version=%lu, if_daddr=%lu}", 
-                               p->if_version, p->if_daddr);
-       }
+       if (p)
+               (void) dump_summary(lfsp, p, DUMP_ALL, NULL);
        else printf("0x0");
        fflush(stdout);
 }
 
        else printf("0x0");
        fflush(stdout);
 }
 
-void
-print_SEGUSE (p)
-       SEGUSE  *p;
+int
+bi_compare(a, b)
+       const void *a;
+       const void *b;
 {
 {
-       if (p) {
-               printf("{su_nbytes=%lu, su_flags=%c%c%c, su_lastmod=",
-                       p->su_nbytes, 
-                       ((p->su_flags & SEGUSE_DIRTY) ? 'D' : 'C'),
-                       ((p->su_flags & SEGUSE_ACTIVE) ? 'A' : ' '),
-                       ((p->su_flags & SEGUSE_SUPERBLOCK) ? 'S' : ' '));
-                       print_time_t(p->su_lastmod);
-                       printf("}");
-       }
-       else 
-               printf("0x0");
-       fflush(stdout);
-}
+       const BLOCK_INFO *ba, *bb;
+       int diff;
+
+       ba = a;
+       bb = b;
+
+       if (diff = (int)(ba->bi_inode - bb->bi_inode))
+               return (diff);
+       if (diff = (int)(ba->bi_lbn - bb->bi_lbn))
+               return (diff);
+       if (diff = (int)(ba->bi_segcreate - bb->bi_segcreate))
+               return (diff);
+       diff = (int)(ba->bi_daddr - bb->bi_daddr);
+       return (diff);
+}      
 
 
-void
-print_CLEANERINFO (p)
-       CLEANERINFO     *p;
+int
+bi_toss(dummy, a, b)
+       const void *dummy;
+       const void *a;
+       const void *b;
 {
 {
-       if (p) printf("{clean=%lu, dirty=%lu}", p->clean, p->dirty);
-       else printf("0x0");
-       fflush(stdout);
-}
+       const BLOCK_INFO *ba, *bb;
 
 
-void
-print_SEGSUM (p)
-       SEGSUM  *p;
-{
-       if (p) {
-               printf("{ss_sumsum=%lu, ss_datasum=%lu, ss_next=%lu, ",
-                       p->ss_sumsum, p->ss_datasum, p->ss_next);
-               printf("ss_create=%lu, ss_nfinfo=%lu, ss_ninos=%lu",
-                       p->ss_create, p->ss_nfinfo, p->ss_ninos);
-               printf("}");
-       }
-       else printf("0x0");
-       fflush(stdout);
+       ba = a;
+       bb = b;
+
+       return(ba->bi_inode == bb->bi_inode && ba->bi_lbn == bb->bi_lbn);
 }
 
 }
 
-void
-print_time_t (t)
-       time_t  t;
+/*
+ * Right now, we never look at the actually data being
+ * passed to the kernel in iip->ii_dinode.  Therefore,
+ * if the same inode appears twice in the same block
+ * (i.e.  has the same disk address), it doesn't matter
+ * which entry we pass.  However, if we get the kernel
+ * to start looking at the dinode, then we will care
+ * and we'll need some way to distinguish which inode
+ * is the more recent one.
+ */
+int
+ii_compare(a, b)
+       const void *a;
+       const void *b;
 {
 {
-       char temp[128];
-       int len;
-
-       strcpy (temp, ctime(&t));
-       len = strlen(temp);
-       if (temp[len-1] == '\n') temp[len-1] = 0;
-       printf("%s", temp);
-       fflush(stdout);
+       const INODE_INFO *ia, *ib;
+       int diff;
+
+       ia = a;
+       ib = b;
+
+       if (diff = (int)(ia->ii_inode - ib->ii_inode))
+               return (diff);
+       if (diff = (int)(ia->ii_segcreate - ib->ii_segcreate))
+               return (diff);
+       diff = (int)(ia->ii_daddr - ib->ii_daddr);
+       return (diff);
 }
 
 }
 
-void
-print_FINFO (p)
-       FINFO   *p;
+int
+ii_toss(dummy, a, b)
+       const void *dummy;
+       const void *a;
+       const void *b;
 {
 {
-       int i;
+       const INODE_INFO *ia, *ib;
 
 
-       if (p) {
-               printf("{fi_nblocks=%lu, fi_version=%lu, fi_ino=%lu, fi_blocks={",
-                       p->fi_nblocks, p->fi_version, p->fi_ino);
-               for (i = 0 ; i < p->fi_nblocks ; i ++) {
-                       if (i > 0) printf(", ");
-                       printf("%ld", p->fi_blocks[i]);
-               }
-               printf("}}");
-       } else printf("0x0");
-       fflush(stdout);
-}
+       ia = a;
+       ib = b;
 
 
-void
-print_BLOCK_INFO (p)
-       BLOCK_INFO      *p;
-{
-       if (p) {
-               printf("{bi_inode=%lu, bi_lbn=%ld, bi_daddr=%lu, bi_segcreate=",
-                       p->bi_inode, p->bi_lbn, p->bi_daddr);
-               print_time_t(p->bi_segcreate);
-               printf(", bi_bp = 0x%x}", p->bi_bp);
-       }
-       else
-               printf("0x0");
-       fflush(stdout);
+       return(ia->ii_inode == ib->ii_inode);
 }
 
 void
 }
 
 void
-print_INODE_INFO (p)
-       INODE_INFO      *p;
+toss(p, nump, size, dotoss, client)
+       void *p;
+       int *nump;
+       size_t size;
+       int (*dotoss) __P((const void *, const void *, const void *));
+       void *client;
 {
 {
-       if (p) {
-               printf("{ii_inode=%lu, ii_daddr=%lu, ii_segcreate=",
-                       p->ii_inode, p->ii_daddr);
-               print_time_t (p->ii_segcreate);
-               printf(", ii_dinode=0x%x}", p->ii_dinode);
-       }
-       else
-               printf("0x0");
-       fflush(stdout);
-}
+       int i;
+       void *p1;
 
 
-void
-print_lfs (p)
-       struct  lfs     *p;
-{
-       int     i;
-       
-       if (p) {
-               printf("{\n");
-               printf("\tlfs_magic=0x%x\n", p->lfs_magic);
-               printf("\tlfs_version=%lu\n", p->lfs_version);
-               printf("\tlfs_size=%lu\n", p->lfs_size);
-               printf("\tlfs_ssize=%lu\n", p->lfs_ssize);
-               printf("\tlfs_dsize=%lu\n", p->lfs_dsize);
-               printf("\tlfs_bsize=%lu\n", p->lfs_bsize);
-               printf("\tlfs_fsize=%lu\n", p->lfs_fsize);
-               printf("\tlfs_frag=%lu\n", p->lfs_frag);
-               /* checkpoint region */
-               printf("\tlfs_free=%lu\n", p->lfs_free);
-               printf("\tlfs_bfree=%lu\n", p->lfs_bfree);
-               printf("\tlfs_nfiles=%lu\n", p->lfs_nfiles);
-               printf("\tlfs_idaddr=%lu\n", p->lfs_idaddr);
-               printf("\tlfs_ifile=%lu\n", p->lfs_ifile);
-               printf("\tlfs_lastseg=%lu\n", p->lfs_lastseg);
-               printf("\tlfs_nextseg=%lu\n", p->lfs_nextseg);
-               printf("\tlfs_curseg=%lu\n", p->lfs_curseg);
-               printf("\tlfs_offset=%lu\n", p->lfs_offset);
-               printf("\tlfs_tstamp=%lu\n", p->lfs_tstamp);
-               /* configuration parameters */
-               printf("\tlfs_minfree=%lu\n", p->lfs_minfree);
-               /* these fields can be computed from the others */
-               printf("\tlfs_dbpseg=%lu\n", p->lfs_dbpseg);
-               printf("\tlfs_inopb=%lu\n", p->lfs_inopb);
-               printf("\tlfs_ifpb=%lu\n", p->lfs_ifpb);
-               printf("\tlfs_sepb=%lu\n", p->lfs_sepb);
-               printf("\tlfs_nindir=%lu\n", p->lfs_nindir);
-               printf("\tlfs_nseg=%lu\n", p->lfs_nseg);
-               printf("\tlfs_nspf=%lu\n", p->lfs_nspf);
-               printf("\tlfs_cleansz=%lu\n", p->lfs_cleansz);
-               printf("\tlfs_segtabsz=%lu\n", p->lfs_segtabsz);
-
-               printf("\tlfs_segmask=%lu\n", p->lfs_segmask);
-               printf("\tlfs_segshift=%lu\n", p->lfs_segshift);
-               printf("\tlfs_bmask=%lu\n", p->lfs_bmask);
-               printf("\tlfs_bshift=%lu\n", p->lfs_bshift);
-               printf("\tlfs_ffmask=%lu\n", p->lfs_ffmask);
-               printf("\tlfs_ffshift=%lu\n", p->lfs_ffshift);
-               printf("\tlfs_fbmask=%lu\n", p->lfs_fbmask);
-               printf("\tlfs_fbshift=%lu\n", p->lfs_fbshift);
-               printf("\tlfs_fsbtodb=%lu\n", p->lfs_fsbtodb);
-               /* superblock offsets */
-               printf("\tlfs_sboffs={");
-               for (i = 0 ; i < LFS_MAXNUMSB ; i ++) {
-                       if (i > 0) printf(", ");
-                       printf("%lu", p->lfs_sboffs[i]);
-               }
-               printf("}\n");
+       if (*nump == 0)
+               return;
 
 
-               printf("}");
+       for (i = *nump; --i > 0;) {
+               p1 = p + size;
+               if (dotoss(client, p, p1)) {
+                       bcopy(p1, p, i * size);
+                       --(*nump);
+               } else 
+                       p += size;
        }
        }
-       else
-               printf("0x0");
-       fflush(stdout);
 }
 }