Ensure that all allocated data structures in fsck_ffs are freed.

Several large data structures are allocated by fsck_ffs to track
resource usage. Most but not all were deallocated at the end of
checking each filesystem. This commit consolidates the freeing
of all data structures in one place and adds one that had previously
been missing.

It is important to clean up these data structures as they can be
large. If the previous allocations have not been freed, fsck_ffs
can run out of address space when many large filesystems are being
checked. An alternative would be to fork a new instance of fsck_ffs
for each filesystem to be checked, but we choose to free the small
set of large structures to save the fork overhead.

Reported by:  Chuck Silvers
Tested by:    Chuck Silvers
MFC after:    7 days
Sponsored by: Netflix
This commit is contained in:
Kirk McKusick 2021-04-02 11:57:34 -07:00
parent a04906f027
commit fc56fd262d
4 changed files with 40 additions and 19 deletions

View File

@ -236,10 +236,12 @@ extern int sujrecovery; /* 1 => doing check using the journal */
} while (0) } while (0)
#define initbarea(bp, type) do { \ #define initbarea(bp, type) do { \
(bp)->b_bno = (ufs2_daddr_t)-1; \ (bp)->b_bno = (ufs2_daddr_t)-1; \
(bp)->b_size = 0; \
(bp)->b_errs = 0; \
(bp)->b_flags = 0; \ (bp)->b_flags = 0; \
(bp)->b_type = type; \
(bp)->b_refcnt = 0; \ (bp)->b_refcnt = 0; \
(bp)->b_index = 0; \ (bp)->b_index = 0; \
(bp)->b_type = type; \
} while (0) } while (0)
#define sbdirty() dirty(&sblk) #define sbdirty() dirty(&sblk)

View File

@ -84,7 +84,6 @@ static LIST_HEAD(bufhash, bufarea) bufhashhd[HASHSIZE]; /* buffer hash list */
static int numbufs; /* size of buffer cache */ static int numbufs; /* size of buffer cache */
static int cachelookups; /* number of cache lookups */ static int cachelookups; /* number of cache lookups */
static int cachereads; /* number of cache reads */ static int cachereads; /* number of cache reads */
static struct bufarea *cgbufs; /* header for cylinder group cache */
static int flushtries; /* number of tries to reclaim memory */ static int flushtries; /* number of tries to reclaim memory */
char *buftype[BT_NUMBUFTYPES] = BT_NAMES; char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
@ -187,13 +186,9 @@ bufinit(void)
{ {
int i; int i;
pdirbp = (struct bufarea *)0; if ((cgblk.b_un.b_buf = Malloc((unsigned int)sblock.fs_bsize)) == NULL)
bzero(&cgblk, sizeof(struct bufarea));
cgblk.b_un.b_buf = Malloc((unsigned int)sblock.fs_bsize);
if (cgblk.b_un.b_buf == NULL)
errx(EEXIT, "Initial malloc(%d) failed", sblock.fs_bsize); errx(EEXIT, "Initial malloc(%d) failed", sblock.fs_bsize);
initbarea(&cgblk, BT_CYLGRP); initbarea(&cgblk, BT_CYLGRP);
cgbufs = NULL;
numbufs = cachelookups = cachereads = 0; numbufs = cachelookups = cachereads = 0;
TAILQ_INIT(&bufqueuehd); TAILQ_INIT(&bufqueuehd);
for (i = 0; i < HASHSIZE; i++) for (i = 0; i < HASHSIZE; i++)
@ -559,7 +554,8 @@ void
ckfini(int markclean) ckfini(int markclean)
{ {
struct bufarea *bp, *nbp; struct bufarea *bp, *nbp;
int ofsmodified, cnt; struct inoinfo *inp, *ninp;
int ofsmodified, cnt, cg, i;
if (bkgrdflag) { if (bkgrdflag) {
unlink(snapname); unlink(snapname);
@ -609,16 +605,20 @@ ckfini(int markclean)
free(cgbufs[cnt].b_un.b_cg); free(cgbufs[cnt].b_un.b_cg);
} }
free(cgbufs); free(cgbufs);
cgbufs = NULL;
} }
flush(fswritefd, &cgblk); flush(fswritefd, &cgblk);
free(cgblk.b_un.b_buf); free(cgblk.b_un.b_buf);
cgblk.b_un.b_buf = NULL;
cnt = 0; cnt = 0;
/* Step 2: indirect, directory, external attribute, and data blocks */ /* Step 2: indirect, directory, external attribute, and data blocks */
if (debug) if (debug)
printf("Flush indirect, directory, external attribute, " printf("Flush indirect, directory, external attribute, "
"and data blocks\n"); "and data blocks\n");
if (pdirbp != NULL) if (pdirbp != NULL) {
brelse(pdirbp); brelse(pdirbp);
pdirbp = NULL;
}
TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) {
switch (bp->b_type) { switch (bp->b_type) {
/* These should not be in the buffer cache list */ /* These should not be in the buffer cache list */
@ -658,8 +658,10 @@ ckfini(int markclean)
/* Step 3: inode blocks */ /* Step 3: inode blocks */
if (debug) if (debug)
printf("Flush inode blocks\n"); printf("Flush inode blocks\n");
if (icachebp != NULL) if (icachebp != NULL) {
brelse(icachebp); brelse(icachebp);
icachebp = NULL;
}
TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) { TAILQ_FOREACH_REVERSE_SAFE(bp, &bufqueuehd, bufqueue, b_list, nbp) {
if (debug && bp->b_refcnt != 0) { if (debug && bp->b_refcnt != 0) {
prtbuf("ckfini: clearing in-use buffer", bp); prtbuf("ckfini: clearing in-use buffer", bp);
@ -686,7 +688,6 @@ ckfini(int markclean)
sbdirty(); sbdirty();
flush(fswritefd, &sblk); flush(fswritefd, &sblk);
} }
pdirbp = (struct bufarea *)0;
if (cursnapshot == 0 && sblock.fs_clean != markclean) { if (cursnapshot == 0 && sblock.fs_clean != markclean) {
if ((sblock.fs_clean = markclean) != 0) { if ((sblock.fs_clean = markclean) != 0) {
sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK); sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
@ -711,6 +712,32 @@ ckfini(int markclean)
rerun = 1; rerun = 1;
} }
} }
/*
* Free allocated tracking structures.
*/
if (blockmap != NULL)
free(blockmap);
blockmap = NULL;
if (inostathead != NULL) {
for (cg = 0; cg < sblock.fs_ncg; cg++)
if (inostathead[cg].il_stat != NULL)
free((char *)inostathead[cg].il_stat);
free(inostathead);
}
inostathead = NULL;
if (inpsort != NULL)
free(inpsort);
inpsort = NULL;
if (inphead != NULL) {
for (i = 0; i < dirhash; i++) {
for (inp = inphead[i]; inp != NULL; inp = ninp) {
ninp = inp->i_nexthash;
free(inp);
}
}
free(inphead);
}
inphead = NULL;
finalIOstats(); finalIOstats();
(void)close(fsreadfd); (void)close(fsreadfd);
(void)close(fswritefd); (void)close(fswritefd);

View File

@ -128,7 +128,6 @@ fsckinit(void)
bzero(totalreadtime, sizeof(struct timespec) * BT_NUMBUFTYPES); bzero(totalreadtime, sizeof(struct timespec) * BT_NUMBUFTYPES);
bzero(&startprog, sizeof(struct timespec)); bzero(&startprog, sizeof(struct timespec));
bzero(&sblk, sizeof(struct bufarea)); bzero(&sblk, sizeof(struct bufarea));
pdirbp = NULL;
cursnapshot = 0; cursnapshot = 0;
listmax = numdirs = dirhash = inplast = 0; listmax = numdirs = dirhash = inplast = 0;
countdirs = 0; countdirs = 0;
@ -159,7 +158,6 @@ fsckinit(void)
fsreadfd = 0; fsreadfd = 0;
fswritefd = 0; fswritefd = 0;
maxfsblock = 0; maxfsblock = 0;
blockmap = NULL;
maxino = 0; maxino = 0;
lfdir = 0; lfdir = 0;
lfname = "lost+found"; lfname = "lost+found";

View File

@ -243,7 +243,6 @@ checkfilesys(char *filesys)
char errmsg[255]; char errmsg[255];
int ofsmodified; int ofsmodified;
int iovlen; int iovlen;
int cylno;
intmax_t blks, files; intmax_t blks, files;
size_t size; size_t size;
@ -627,11 +626,6 @@ checkfilesys(char *filesys)
resolved = 0; resolved = 0;
ckfini(resolved); ckfini(resolved);
for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
if (inostathead[cylno].il_stat != NULL)
free((char *)inostathead[cylno].il_stat);
free((char *)inostathead);
inostathead = NULL;
if (fsmodified && !preen) if (fsmodified && !preen)
printf("\n***** FILE SYSTEM WAS MODIFIED *****\n"); printf("\n***** FILE SYSTEM WAS MODIFIED *****\n");
if (rerun) { if (rerun) {