On Sun, Jun 21, 2020 at 03:35:21PM +0200, Otto Moerbeek wrote:

> 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.

Any takers?

        -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