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); > } > >