From ddfa9b895b20fc04a73aee44c52f2db7b47d48b6 Mon Sep 17 00:00:00 2001 From: mckusick Date: Fri, 26 Feb 2010 21:49:11 +0000 Subject: MFC of 203763, 203764, 203768, 203769, 203770, 203782, and 203784. These fixes correct a problem in the file system that treats large inode numbers as negative rather than unsigned. For a default (16K block) file system, this bug began to show up at a file system size above about 16Tb. These fixes also update newfs to ensure that it will never create a filesystem with more than 2^32 inodes. They also update libufs, tunefs, and growfs so that they properly handle inode numbers as unsigned. Reported by: Scott Burns, John Kilburg, and Bruce Evans Followup by: Jeff Roberson PR: 133980 --- sbin/growfs/growfs.c | 16 +++++++------- sbin/newfs/mkfs.c | 59 ++++++++++++++++++++++++++++++++++++++++++---------- sbin/newfs/newfs.c | 46 ---------------------------------------- sbin/newfs/newfs.h | 32 ++++++++++++++++++++++++++++ sbin/tunefs/tunefs.c | 4 ++-- 5 files changed, 90 insertions(+), 67 deletions(-) (limited to 'sbin') diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index cc58fc6..bf803ac 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -174,10 +174,9 @@ static void growfs(int fsi, int fso, unsigned int Nflag) { DBG_FUNC("growfs") - int i; - int cylno, j; time_t utime; - int width; + uint cylno; + int i, j, width; char tmpbuf[100]; #ifdef FSIRAND static int randinit=0; @@ -373,10 +372,11 @@ initcg(int cylno, time_t utime, int fso, unsigned int Nflag) { DBG_FUNC("initcg") static void *iobuf; - long d, dlower, dupper, blkno, start; + long blkno, start; ufs2_daddr_t i, cbase, dmax; struct ufs1_dinode *dp1; struct csum *cs; + uint d, dupper, dlower; if (iobuf == NULL && (iobuf = malloc(sblock.fs_bsize)) == NULL) { errx(37, "panic: cannot allocate I/O buffer"); @@ -431,7 +431,7 @@ initcg(int cylno, time_t utime, int fso, unsigned int Nflag) acg.cg_nextfreeoff = acg.cg_clusteroff + howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); } - if (acg.cg_nextfreeoff > sblock.fs_cgsize) { + if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) { /* * This should never happen as we would have had that panic * already on file system creation @@ -746,7 +746,7 @@ updjcg(int cylno, time_t utime, int fsi, int fso, unsigned int Nflag) * needed, update the free space in the superblock. */ acg.cg_time = utime; - if (cylno == sblock.fs_ncg - 1) { + if ((unsigned)cylno == sblock.fs_ncg - 1) { /* * This is still the last cylinder group. */ @@ -940,8 +940,8 @@ updcsloc(time_t utime, int fsi, int fso, unsigned int Nflag) int ocscg, ncscg; int blocks; ufs2_daddr_t cbase, dupper, odupper, d, f, g; - int ind; - int cylno, inc; + int ind, inc; + uint cylno; struct gfs_bpp *bp; int i, l; int lcs=0; diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index f99cb14..b7a6b52 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -114,10 +114,13 @@ void mkfs(struct partition *pp, char *fsys) { int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; - long i, j, cylno, csfrags; + long i, j, csfrags; + uint cg; time_t utime; quad_t sizepb; int width; + ino_t maxinum; + int minfragsperinode; /* minimum ratio of frags to inodes */ char tmpbuf[100]; /* XXX this will break in about 2,500 years */ union { struct fs fdummy; @@ -170,6 +173,8 @@ mkfs(struct partition *pp, char *fsys) if (sblock.fs_avgfpdir <= 0) printf("illegal expected number of files per directory %d\n", sblock.fs_avgfpdir), exit(15); + +restart: /* * collect and verify the block and fragment sizes */ @@ -216,6 +221,8 @@ mkfs(struct partition *pp, char *fsys) sblock.fs_fsize, MAXFRAG, sblock.fs_bsize / MAXFRAG); sblock.fs_fsize = sblock.fs_bsize / MAXFRAG; } + if (maxbsize == 0) + maxbsize = bsize; if (maxbsize < bsize || !POWEROF2(maxbsize)) { sblock.fs_maxbsize = sblock.fs_bsize; printf("Extent size set to %d\n", sblock.fs_maxbsize); @@ -225,6 +232,14 @@ mkfs(struct partition *pp, char *fsys) } else { sblock.fs_maxbsize = maxbsize; } + /* + * Maxcontig sets the default for the maximum number of blocks + * that may be allocated sequentially. With file system clustering + * it is possible to allocate contiguous blocks up to the maximum + * transfer size permitted by the controller or buffering. + */ + if (maxcontig == 0) + maxcontig = MAX(1, MAXPHYS / bsize); sblock.fs_maxcontig = maxcontig; if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; @@ -315,9 +330,26 @@ mkfs(struct partition *pp, char *fsys) * can put into each cylinder group. If this is too big, we reduce * the density until it fits. */ + maxinum = (((int64_t)(1)) << 32) - INOPB(&sblock); + minfragsperinode = 1 + fssize / maxinum; + if (density == 0) { + density = MAX(NFPI, minfragsperinode) * fsize; + } else if (density < minfragsperinode * fsize) { + origdensity = density; + density = minfragsperinode * fsize; + fprintf(stderr, "density increased from %d to %d\n", + origdensity, density); + } origdensity = density; for (;;) { fragsperinode = MAX(numfrags(&sblock, density), 1); + if (fragsperinode < minfragsperinode) { + bsize <<= 1; + fsize <<= 1; + printf("Block size too small for a file system %s %d\n", + "of this size. Increasing blocksize to", bsize); + goto restart; + } minfpg = fragsperinode * INOPB(&sblock); if (minfpg > sblock.fs_size) minfpg = sblock.fs_size; @@ -406,7 +438,10 @@ mkfs(struct partition *pp, char *fsys) if (sblock.fs_sbsize > SBLOCKSIZE) sblock.fs_sbsize = SBLOCKSIZE; sblock.fs_minfree = minfree; - sblock.fs_maxbpg = maxbpg; + if (maxbpg == 0) + sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize); + else + sblock.fs_maxbpg = maxbpg; sblock.fs_optim = opt; sblock.fs_cgrotor = 0; sblock.fs_pendingblocks = 0; @@ -476,9 +511,9 @@ mkfs(struct partition *pp, char *fsys) fsdummy.fs_magic = 0; bwrite(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE); - for (i = 0; i < fsdummy.fs_ncg; i++) + for (cg = 0; cg < fsdummy.fs_ncg; cg++) bwrite(&disk, part_ofs + fsbtodb(&fsdummy, - cgsblock(&fsdummy, i)), chdummy, SBLOCKSIZE); + cgsblock(&fsdummy, cg)), chdummy, SBLOCKSIZE); } } if (!Nflag) @@ -516,11 +551,11 @@ mkfs(struct partition *pp, char *fsys) * writing out in each cylinder group. */ bcopy((char *)&sblock, iobuf, SBLOCKSIZE); - for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { - initcg(cylno, utime); + for (cg = 0; cg < sblock.fs_ncg; cg++) { + initcg(cg, utime); j = snprintf(tmpbuf, sizeof(tmpbuf), " %jd%s", - (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cylno)), - cylno < (sblock.fs_ncg-1) ? "," : ""); + (intmax_t)fsbtodb(&sblock, cgsblock(&sblock, cg)), + cg < (sblock.fs_ncg-1) ? "," : ""); if (j < 0) tmpbuf[j = 0] = '\0'; if (i + j >= width) { @@ -574,7 +609,8 @@ mkfs(struct partition *pp, char *fsys) void initcg(int cylno, time_t utime) { - long i, j, d, dlower, dupper, blkno, start; + long blkno, start; + uint i, j, d, dlower, dupper; ufs2_daddr_t cbase, dmax; struct ufs1_dinode *dp1; struct ufs2_dinode *dp2; @@ -631,7 +667,7 @@ initcg(int cylno, time_t utime) acg.cg_nextfreeoff = acg.cg_clusteroff + howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); } - if (acg.cg_nextfreeoff > sblock.fs_cgsize) { + if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) { printf("Panic: cylinder group too big\n"); exit(37); } @@ -880,7 +916,8 @@ makedir(struct direct *protodir, int entries) ufs2_daddr_t alloc(int size, int mode) { - int i, d, blkno, frag; + int i, blkno, frag; + uint d; bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg, sblock.fs_cgsize); diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c index b70ce1b..8867306 100644 --- a/sbin/newfs/newfs.c +++ b/sbin/newfs/newfs.c @@ -79,38 +79,6 @@ __FBSDID("$FreeBSD$"); #include "newfs.h" -/* - * The following two constants set the default block and fragment sizes. - * Both constants must be a power of 2 and meet the following constraints: - * MINBSIZE <= DESBLKSIZE <= MAXBSIZE - * sectorsize <= DESFRAGSIZE <= DESBLKSIZE - * DESBLKSIZE / DESFRAGSIZE <= 8 - */ -#define DFL_FRAGSIZE 2048 -#define DFL_BLKSIZE 16384 - -/* - * Cylinder groups may have up to MAXBLKSPERCG blocks. The actual - * number used depends upon how much information can be stored - * in a cylinder group map which must fit in a single file system - * block. The default is to use as many as possible blocks per group. - */ -#define MAXBLKSPERCG 0x7fffffff /* desired fs_fpg ("infinity") */ - -/* - * MAXBLKPG determines the maximum number of data blocks which are - * placed in a single cylinder group. The default is one indirect - * block worth of data blocks. - */ -#define MAXBLKPG(bsize) ((bsize) / sizeof(ufs2_daddr_t)) - -/* - * Each file system has a number of inodes statically allocated. - * We allocate one inode slot per NFPI fragments, expecting this - * to be far more than we will ever need. - */ -#define NFPI 4 - int Eflag; /* Erase previous disk contents */ int Lflag; /* add a volume label */ int Nflag; /* run without writing file system */ @@ -387,25 +355,11 @@ main(int argc, char *argv[]) fsize = MAX(DFL_FRAGSIZE, sectorsize); if (bsize <= 0) bsize = MIN(DFL_BLKSIZE, 8 * fsize); - if (maxbsize == 0) - maxbsize = bsize; - /* - * Maxcontig sets the default for the maximum number of blocks - * that may be allocated sequentially. With file system clustering - * it is possible to allocate contiguous blocks up to the maximum - * transfer size permitted by the controller or buffering. - */ - if (maxcontig == 0) - maxcontig = MAX(1, MAXPHYS / bsize); - if (density == 0) - density = NFPI * fsize; if (minfree < MINFREE && opt != FS_OPTSPACE) { fprintf(stderr, "Warning: changing optimization to space "); fprintf(stderr, "because minfree is less than %d%%\n", MINFREE); opt = FS_OPTSPACE; } - if (maxbpg == 0) - maxbpg = MAXBLKPG(bsize); realsectorsize = sectorsize; if (sectorsize != DEV_BSIZE) { /* XXX */ int secperblk = sectorsize / DEV_BSIZE; diff --git a/sbin/newfs/newfs.h b/sbin/newfs/newfs.h index 0d7cb62..9da3226 100644 --- a/sbin/newfs/newfs.h +++ b/sbin/newfs/newfs.h @@ -41,6 +41,38 @@ #include /* + * The following two constants set the default block and fragment sizes. + * Both constants must be a power of 2 and meet the following constraints: + * MINBSIZE <= DESBLKSIZE <= MAXBSIZE + * sectorsize <= DESFRAGSIZE <= DESBLKSIZE + * DESBLKSIZE / DESFRAGSIZE <= 8 + */ +#define DFL_FRAGSIZE 2048 +#define DFL_BLKSIZE 16384 + +/* + * Cylinder groups may have up to MAXBLKSPERCG blocks. The actual + * number used depends upon how much information can be stored + * in a cylinder group map which must fit in a single file system + * block. The default is to use as many as possible blocks per group. + */ +#define MAXBLKSPERCG 0x7fffffff /* desired fs_fpg ("infinity") */ + +/* + * MAXBLKPG determines the maximum number of data blocks which are + * placed in a single cylinder group. The default is one indirect + * block worth of data blocks. + */ +#define MAXBLKPG(bsize) ((bsize) / sizeof(ufs2_daddr_t)) + +/* + * Each file system has a number of inodes statically allocated. + * We allocate one inode slot per NFPI fragments, expecting this + * to be far more than we will ever need. + */ +#define NFPI 4 + +/* * variables set up by front end. */ extern int Eflag; /* Erase previous disk contents */ diff --git a/sbin/tunefs/tunefs.c b/sbin/tunefs/tunefs.c index 2b263bb..57dfbcb 100644 --- a/sbin/tunefs/tunefs.c +++ b/sbin/tunefs/tunefs.c @@ -286,7 +286,7 @@ main(int argc, char *argv[]) } if (fflag) { name = "average file size"; - if (sblock.fs_avgfilesize == fvalue) { + if (sblock.fs_avgfilesize == (unsigned)fvalue) { warnx("%s remains unchanged as %d", name, fvalue); } else { @@ -389,7 +389,7 @@ main(int argc, char *argv[]) } if (sflag) { name = "expected number of files per directory"; - if (sblock.fs_avgfpdir == svalue) { + if (sblock.fs_avgfpdir == (unsigned)svalue) { warnx("%s remains unchanged as %d", name, svalue); } else { -- cgit v1.1