Hi,

both phase 1 and phase 5 need cylinder group metadata.  This diff
keeps the cg data read in phase 1 in memory to be used by phase 5 if
possible. From FreeBSD. 

        -Otto

On an empty 30T fileystem:

$ time obj/fsck_ffs -f /dev/sd3a
    2m44.10s real     0m13.21s user     0m07.38s system

$ time doas obj/fsck_ffs -f /dev/sd3a
    1m32.81s real     0m12.86s user     0m05.25s system

The difference will be less if a fileystem is filled up, but still nice.

        -Otto

Index: fsck.h
===================================================================
RCS file: /cvs/src/sbin/fsck_ffs/fsck.h,v
retrieving revision 1.32
diff -u -p -r1.32 fsck.h
--- fsck.h      5 Jan 2018 09:33:47 -0000       1.32
+++ fsck.h      21 Jun 2020 12:48:50 -0000
@@ -136,7 +136,6 @@ struct bufarea {
 struct bufarea bufhead;                /* head of list of other blks in 
filesys */
 struct bufarea sblk;           /* file system superblock */
 struct bufarea asblk;          /* alternate file system superblock */
-struct bufarea cgblk;          /* cylinder group blocks */
 struct bufarea *pdirbp;                /* current directory contents */
 struct bufarea *pbp;           /* current inode block */
 struct bufarea *getdatablk(daddr_t, long);
@@ -148,9 +147,7 @@ struct bufarea *getdatablk(daddr_t, long
        (bp)->b_flags = 0;
 
 #define        sbdirty()       sblk.b_dirty = 1
-#define        cgdirty()       cgblk.b_dirty = 1
 #define        sblock          (*sblk.b_un.b_fs)
-#define        cgrp            (*cgblk.b_un.b_cg)
 
 enum fixstate {DONTKNOW, NOFIX, FIX, IGNORE};
 
@@ -275,9 +272,13 @@ struct ufs2_dinode ufs2_zino;
 #define        FOUND   0x10
 
 union dinode *ginode(ino_t);
+struct bufarea *cglookup(u_int cg);
 struct inoinfo *getinoinfo(ino_t);
 void getblk(struct bufarea *, daddr_t, long);
 ino_t allocino(ino_t, int);
+void *Malloc(size_t);
+void *Calloc(size_t, size_t);
+void *Reallocarray(void *, size_t, size_t);
 
 int    (*info_fn)(char *, size_t);
 char   *info_filesys;
Index: inode.c
===================================================================
RCS file: /cvs/src/sbin/fsck_ffs/inode.c,v
retrieving revision 1.49
diff -u -p -r1.49 inode.c
--- inode.c     16 Sep 2018 02:43:11 -0000      1.49
+++ inode.c     21 Jun 2020 12:48:50 -0000
@@ -370,7 +370,7 @@ setinodebuf(ino_t inum)
                partialsize = inobufsize;
        }
        if (inodebuf == NULL &&
-           (inodebuf = malloc((unsigned)inobufsize)) == NULL)
+           (inodebuf = Malloc((unsigned)inobufsize)) == NULL)
                errexit("Cannot allocate space for inode buffer\n");
 }
 
@@ -401,7 +401,7 @@ cacheino(union dinode *dp, ino_t inumber
        blks = howmany(DIP(dp, di_size), sblock.fs_bsize);
        if (blks > NDADDR)
                blks = NDADDR + NIADDR;
-       inp = malloc(sizeof(*inp) + (blks ? blks - 1 : 0) * sizeof(daddr_t));
+       inp = Malloc(sizeof(*inp) + (blks ? blks - 1 : 0) * sizeof(daddr_t));
        if (inp == NULL)
                errexit("cannot allocate memory for inode cache\n");
        inpp = &inphead[inumber % numdirs];
@@ -423,10 +423,10 @@ cacheino(union dinode *dp, ino_t inumber
                        inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]);
        if (inplast == listmax) {
                newlistmax = listmax + 100;
-               newinpsort = reallocarray(inpsort,
+               newinpsort = Reallocarray(inpsort,
                    (unsigned)newlistmax, sizeof(struct inoinfo *));
                if (newinpsort == NULL)
-                       errexit("cannot increase directory list");
+                       errexit("cannot increase directory list\n");
                inpsort = newinpsort;
                listmax = newlistmax;
        }
@@ -582,7 +582,8 @@ allocino(ino_t request, int type)
 {
        ino_t ino;
        union dinode *dp;
-       struct cg *cgp = &cgrp;
+       struct bufarea *cgbp;
+       struct cg *cgp;
        int cg;
        time_t t;
        struct inostat *info;
@@ -602,7 +603,7 @@ allocino(ino_t request, int type)
                unsigned long newalloced, i;
                newalloced = MINIMUM(sblock.fs_ipg,
                        MAXIMUM(2 * inostathead[cg].il_numalloced, 10));
-               info = calloc(newalloced, sizeof(struct inostat));
+               info = Calloc(newalloced, sizeof(struct inostat));
                if (info == NULL) {
                        pwarn("cannot alloc %zu bytes to extend inoinfo\n",
                                sizeof(struct inostat) * newalloced);
@@ -619,7 +620,8 @@ allocino(ino_t request, int type)
                inostathead[cg].il_numalloced = newalloced;
                info = inoinfo(ino);
        }
-       getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
+       cgbp = cglookup(cg);
+       cgp = cgbp->b_un.b_cg;
        if (!cg_chkmagic(cgp))
                pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
        setbit(cg_inosused(cgp), ino % sblock.fs_ipg);
@@ -637,7 +639,7 @@ allocino(ino_t request, int type)
        default:
                return (0);
        }
-       cgdirty();
+       dirty(cgbp);
        dp = ginode(ino);
        DIP_SET(dp, di_db[0],  allocblk(1));
        if (DIP(dp, di_db[0]) == 0) {
Index: pass1.c
===================================================================
RCS file: /cvs/src/sbin/fsck_ffs/pass1.c,v
retrieving revision 1.46
diff -u -p -r1.46 pass1.c
--- pass1.c     20 Jun 2020 07:49:04 -0000      1.46
+++ pass1.c     21 Jun 2020 12:48:50 -0000
@@ -66,6 +66,8 @@ pass1(void)
        ino_t inumber, inosused, ninosused;
        size_t inospace;
        struct inostat *info;
+       struct bufarea *cgbp;
+       struct cg *cgp;
        u_int c;
        struct inodesc idesc;
        daddr_t i, cgd;
@@ -99,9 +101,10 @@ pass1(void)
        for (c = 0; c < sblock.fs_ncg; c++) {
                inumber = c * sblock.fs_ipg;
                setinodebuf(inumber);
-               getblk(&cgblk, cgtod(&sblock, c), sblock.fs_cgsize);
+               cgbp = cglookup(c);
+               cgp = cgbp->b_un.b_cg;
                if (sblock.fs_magic == FS_UFS2_MAGIC) {
-                       inosused = cgrp.cg_initediblk;
+                       inosused = cgp->cg_initediblk;
                        if (inosused > sblock.fs_ipg)
                                inosused = sblock.fs_ipg;
                } else
@@ -115,7 +118,7 @@ pass1(void)
                 * read only those inodes in from disk.
                 */
                if (preen && usedsoftdep) {
-                       cp = &cg_inosused(&cgrp)[(inosused - 1) / CHAR_BIT];
+                       cp = &cg_inosused(cgp)[(inosused - 1) / CHAR_BIT];
                        for ( ; inosused != 0; cp--) {
                                if (*cp == 0) {
                                        if (inosused > CHAR_BIT)
@@ -140,10 +143,10 @@ pass1(void)
                        inostathead[c].il_stat = 0;
                        continue;
                }
-               info = calloc((unsigned)inosused, sizeof(struct inostat));
+               info = Calloc((unsigned)inosused, sizeof(struct inostat));
                inospace = (unsigned)inosused * sizeof(struct inostat);
                if (info == NULL)
-                       errexit("cannot alloc %zu bytes for inoinfo", inospace);
+                       errexit("cannot alloc %zu bytes for inoinfo\n", 
inospace);
                inostathead[c].il_stat = info;
                /*
                 * Scan the allocated inodes.
@@ -179,7 +182,7 @@ pass1(void)
                        struct inostat *ninfo;
                        size_t ninospace;
 
-                       ninfo = reallocarray(info, ninosused, sizeof(*ninfo));
+                       ninfo = Reallocarray(info, ninosused, sizeof(*ninfo));
                        if (ninfo == NULL) {
                                pfatal("too many inodes %llu, or out of 
memory\n",
                                    (unsigned long long)ninosused);
@@ -300,7 +303,7 @@ checkinode(ino_t inumber, struct inodesc
        n_files++;
        ILNCOUNT(inumber) = DIP(dp, di_nlink);
        if (DIP(dp, di_nlink) <= 0) {
-               zlnp = malloc(sizeof *zlnp);
+               zlnp = Malloc(sizeof *zlnp);
                if (zlnp == NULL) {
                        pfatal("LINK COUNT TABLE OVERFLOW");
                        if (reply("CONTINUE") == 0) {
@@ -392,7 +395,7 @@ pass1check(struct inodesc *idesc)
                                }
                                return (STOP);
                        }
-                       new = malloc(sizeof(struct dups));
+                       new = Malloc(sizeof(struct dups));
                        if (new == NULL) {
                                pfatal("DUP TABLE OVERFLOW.");
                                if (reply("CONTINUE") == 0) {
Index: pass5.c
===================================================================
RCS file: /cvs/src/sbin/fsck_ffs/pass5.c,v
retrieving revision 1.49
diff -u -p -r1.49 pass5.c
--- pass5.c     20 Jun 2020 07:49:04 -0000      1.49
+++ pass5.c     21 Jun 2020 12:48:50 -0000
@@ -65,7 +65,6 @@ pass5(void)
        u_int c;
        int inomapsize, blkmapsize;
        struct fs *fs = &sblock;
-       struct cg *cg = &cgrp;
        daddr_t dbase, dmax;
        daddr_t d;
        long i, k, rewritecg = 0;
@@ -76,6 +75,8 @@ pass5(void)
        char buf[MAXBSIZE];
        struct cg *newcg = (struct cg *)buf;
        struct ocg *ocg = (struct ocg *)buf;
+       struct cg *cg;
+       struct bufarea *cgbp;
 
        memset(newcg, 0, (size_t)fs->fs_cgsize);
        if (cvtlevel >= 3) {
@@ -179,7 +180,8 @@ pass5(void)
        info_fn = pass5_info;
        for (c = 0; c < fs->fs_ncg; c++) {
                info_cg = c;
-               getblk(&cgblk, cgtod(fs, c), fs->fs_cgsize);
+               cgbp = cglookup(c);
+               cg = cgbp->b_un.b_cg;
                if (!cg_chkmagic(cg))
                        pfatal("CG %u: BAD MAGIC NUMBER\n", c);
                dbase = cgbase(fs, c);
@@ -323,13 +325,13 @@ pass5(void)
                }
                if (rewritecg) {
                        memcpy(cg, newcg, (size_t)fs->fs_cgsize);
-                       cgdirty();
+                       dirty(cgbp);
                        continue;
                }
                if (memcmp(newcg, cg, basesize) &&
                    dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
                        memcpy(cg, newcg, (size_t)basesize);
-                       cgdirty();
+                       dirty(cgbp);
                }
                if (usedsoftdep) {
                        for (i = 0; i < inomapsize; i++) {
@@ -364,7 +366,7 @@ pass5(void)
                    dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
                        memmove(cg_inosused(cg), cg_inosused(newcg),
                                (size_t)mapsize);
-                       cgdirty();
+                       dirty(cgbp);
                }
        }
        info_fn = NULL;
Index: utilities.c
===================================================================
RCS file: /cvs/src/sbin/fsck_ffs/utilities.c,v
retrieving revision 1.53
diff -u -p -r1.53 utilities.c
--- utilities.c 20 Jun 2020 07:49:04 -0000      1.53
+++ utilities.c 21 Jun 2020 12:48:50 -0000
@@ -51,7 +51,8 @@
 #include "fsck.h"
 #include "extern.h"
 
-long   diskreads, totalreads;  /* Disk cache statistics */
+long                           diskreads, totalreads;  /* Disk cache 
statistics */
+static struct bufarea          cgblk;                  /* backup buffer for 
cylinder group blocks */
 
 static void rwerror(char *, daddr_t);
 
@@ -176,6 +177,39 @@ bufinit(void)
 }
 
 /*
+ * Manage cylinder group buffers.
+ */
+static struct bufarea *cgbufs; /* header for cylinder group cache */
+static int flushtries;         /* number of tries to reclaim memory */
+struct bufarea *
+cglookup(u_int cg)
+{
+       struct bufarea *cgbp;
+       struct cg *cgp;
+
+       if (cgbufs == NULL) {
+               cgbufs = calloc(sblock.fs_ncg, sizeof(struct bufarea));
+               if (cgbufs == NULL)
+                       errexit("cannot allocate cylinder group buffers");
+       }
+       cgbp = &cgbufs[cg];
+       if (cgbp->b_un.b_cg != NULL)
+               return (cgbp);
+       cgp = NULL;
+       if (flushtries == 0)
+               cgp = malloc((unsigned int)sblock.fs_cgsize);
+       if (cgp == NULL) {
+               getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
+               return (&cgblk);
+       }
+       cgbp->b_un.b_cg = cgp;
+       initbarea(cgbp);
+       getblk(cgbp, cgtod(&sblock, cg), sblock.fs_cgsize);
+       return (cgbp);
+}
+
+
+/*
  * Manage a cache of directory blocks.
  */
 struct bufarea *
@@ -305,6 +339,15 @@ ckfini(int markclean)
        }
        if (bufhead.b_size != cnt)
                errexit("Panic: lost %d buffers\n", bufhead.b_size - cnt);
+       if (cgbufs != NULL) {   
+               for (cnt = 0; cnt < sblock.fs_ncg; cnt++) {
+                       if (cgbufs[cnt].b_un.b_cg == NULL)
+                               continue;
+                       flush(fswritefd, &cgbufs[cnt]);
+                       free(cgbufs[cnt].b_un.b_cg);
+               }
+               free(cgbufs);
+       }
        pbp = pdirbp = NULL;
        if (markclean && (sblock.fs_clean & FS_ISCLEAN) == 0) {
                /*
@@ -400,7 +443,8 @@ allocblk(int frags)
 {
        daddr_t i, baseblk;
        int j, k, cg;
-       struct cg *cgp = &cgrp;
+       struct bufarea *cgbp;
+       struct cg *cgp;
 
        if (frags <= 0 || frags > sblock.fs_frag)
                return (0);
@@ -416,7 +460,8 @@ allocblk(int frags)
                                continue;
                        }
                        cg = dtog(&sblock, i + j);
-                       getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
+                       cgbp = cglookup(cg);
+                       cgp = cgbp->b_un.b_cg;
                        if (!cg_chkmagic(cgp))
                                pfatal("CG %d: BAD MAGIC NUMBER\n", cg);
                        baseblk = dtogd(&sblock, i + j);
@@ -614,4 +659,68 @@ catchinfo(int signo)
                writev(info_fd, iov, 4);
        }
        errno = save_errno;
+}
+/*
+ * Attempt to flush a cylinder group cache entry.
+ * Return whether the flush was successful.
+ */
+static int
+flushentry(void)
+{
+       struct bufarea *cgbp;
+
+       if (flushtries == sblock.fs_ncg || cgbufs == NULL)
+               return (0);
+       cgbp = &cgbufs[flushtries++];
+       if (cgbp->b_un.b_cg == NULL)
+               return (0);
+       flush(fswritefd, cgbp);
+       free(cgbp->b_un.b_buf);
+       cgbp->b_un.b_buf = NULL;
+       return (1);
+}
+
+/*
+ * Wrapper for malloc() that flushes the cylinder group cache to try
+ * to get space.
+ */
+void *
+Malloc(size_t size)
+{
+       void *retval;
+
+       while ((retval = malloc(size)) == NULL)
+               if (flushentry() == 0)
+                       break;
+       return (retval);
+}
+
+/*
+ * Wrapper for calloc() that flushes the cylinder group cache to try
+ * to get space.
+ */
+void*
+Calloc(size_t cnt, size_t size)
+{
+       void *retval;
+
+       while ((retval = calloc(cnt, size)) == NULL)
+               if (flushentry() == 0)
+                       break;
+       return (retval);
+}
+
+/*
+ * Wrapper for reallocarray() that flushes the cylinder group cache to try
+ * to get space.
+ */
+void*
+Reallocarray(void *p, size_t cnt, size_t size)
+{
+       void *retval;
+
+       while ((retval = reallocarray(p, cnt, size)) == NULL)
+               if (flushentry() == 0)
+                       break;
+       return (retval);
 }


Reply via email to