diff options
Diffstat (limited to 'sbin/newfs/mkfs.c')
-rw-r--r-- | sbin/newfs/mkfs.c | 92 |
1 files changed, 63 insertions, 29 deletions
diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index a6c4ee60c2d5..db1fe2991f6d 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -38,15 +38,7 @@ * SUCH DAMAGE. */ -#if 0 -#ifndef lint -static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95"; -#endif /* not lint */ -#endif -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#define IN_RTLD /* So we pickup the P_OSREL defines */ +#define _WANT_P_OSREL #include <sys/param.h> #include <sys/disklabel.h> #include <sys/file.h> @@ -76,6 +68,23 @@ __FBSDID("$FreeBSD$"); #define UMASK 0755 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) +/* + * The definition of "struct cg" used to contain an extra field at the end + * to represent the variable-length data that followed the fixed structure. + * This had the effect of artificially limiting the number of blocks that + * newfs would put in a CG, since newfs thought that the fixed-size header + * was bigger than it really was. When we started validating that the CG + * header data actually fit into one fs block, the placeholder field caused + * a problem because it caused struct cg to be a different size depending on + * platform. The placeholder field was later removed, but this caused a + * backward compatibility problem with older binaries that still thought + * struct cg was larger, and a new file system could fail validation if + * viewed by the older binaries. To avoid this compatibility problem, we + * now artificially reduce the amount of space that the variable-length data + * can use such that new file systems will pass validation by older binaries. + */ +#define CGSIZEFUDGE 8 + static struct csum *fscs; #define sblock disk.d_fs #define acg disk.d_cg @@ -332,6 +341,7 @@ restart: * can put into each cylinder group. If this is too big, we reduce * the density until it fits. */ +retry: maxinum = (((int64_t)(1)) << 32) - INOPB(&sblock); minfragsperinode = 1 + fssize / maxinum; if (density == 0) { @@ -368,7 +378,8 @@ restart: sblock.fs_fpg = minfpg; sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), INOPB(&sblock)); - if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) + if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize - + CGSIZEFUDGE) break; density -= sblock.fs_fsize; } @@ -387,9 +398,11 @@ restart: if (Oflag > 1 || (Oflag == 1 && sblock.fs_ipg <= 0x7fff)) { if (sblock.fs_size / sblock.fs_fpg < MINCYLGRPS) break; - if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) + if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize - + CGSIZEFUDGE) continue; - if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) + if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize - + CGSIZEFUDGE) break; } sblock.fs_fpg -= sblock.fs_frag; @@ -636,23 +649,26 @@ restart: * Read the last sector of the boot block, replace the last * 20 bytes with the recovery information, then write it back. * The recovery information only works for UFS2 filesystems. + * For UFS1, zero out the area to ensure that an old UFS2 + * recovery block is not accidentally found. */ - if (sblock.fs_magic == FS_UFS2_MAGIC) { - if ((fsrbuf = malloc(realsectorsize)) == NULL || bread(&disk, - part_ofs + (SBLOCK_UFS2 - realsectorsize) / disk.d_bsize, - fsrbuf, realsectorsize) == -1) - err(1, "can't read recovery area: %s", disk.d_error); - fsr = - (struct fsrecovery *)&fsrbuf[realsectorsize - sizeof *fsr]; + if ((fsrbuf = malloc(realsectorsize)) == NULL || bread(&disk, + part_ofs + (SBLOCK_UFS2 - realsectorsize) / disk.d_bsize, + fsrbuf, realsectorsize) == -1) + err(1, "can't read recovery area: %s", disk.d_error); + fsr = (struct fsrecovery *)&fsrbuf[realsectorsize - sizeof *fsr]; + if (sblock.fs_magic != FS_UFS2_MAGIC) { + memset(fsr, 0, sizeof *fsr); + } else { fsr->fsr_magic = sblock.fs_magic; fsr->fsr_fpg = sblock.fs_fpg; fsr->fsr_fsbtodb = sblock.fs_fsbtodb; fsr->fsr_sblkno = sblock.fs_sblkno; fsr->fsr_ncg = sblock.fs_ncg; - wtfs((SBLOCK_UFS2 - realsectorsize) / disk.d_bsize, - realsectorsize, fsrbuf); - free(fsrbuf); } + wtfs((SBLOCK_UFS2 - realsectorsize) / disk.d_bsize, + realsectorsize, fsrbuf); + free(fsrbuf); /* * Update information about this partition in pack * label, to that it may be updated on disk. @@ -663,6 +679,21 @@ restart: pp->p_frag = sblock.fs_frag; pp->p_cpg = sblock.fs_fpg; } + /* + * This should NOT happen. If it does complain loudly and + * take evasive action. + */ + if ((int32_t)CGSIZE(&sblock) > sblock.fs_bsize) { + printf("INTERNAL ERROR: ipg %d, fpg %d, contigsumsize %d, ", + sblock.fs_ipg, sblock.fs_fpg, sblock.fs_contigsumsize); + printf("old_cpg %d, size_cg %zu, CGSIZE %zu\n", + sblock.fs_old_cpg, sizeof(struct cg), CGSIZE(&sblock)); + printf("Please file a FreeBSD bug report and include this " + "output\n"); + maxblkspercg = fragstoblks(&sblock, sblock.fs_fpg) - 1; + density = 0; + goto retry; + } } /* @@ -702,7 +733,7 @@ initcg(int cylno, time_t utime) acg.cg_ndblk = dmax - cbase; if (sblock.fs_contigsumsize > 0) acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag; - start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); + start = sizeof(acg); if (Oflag == 2) { acg.cg_iusedoff = start; } else { @@ -730,7 +761,8 @@ initcg(int cylno, time_t utime) howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); } if (acg.cg_nextfreeoff > (unsigned)sblock.fs_cgsize) { - printf("Panic: cylinder group too big\n"); + printf("Panic: cylinder group too big by %d bytes\n", + acg.cg_nextfreeoff - (unsigned)sblock.fs_cgsize); exit(37); } acg.cg_cs.cs_nifree += sblock.fs_ipg; @@ -912,8 +944,9 @@ fsinit(time_t utime) alloc(sblock.fs_fsize, node.dp1.di_mode); node.dp1.di_blocks = btodb(fragroundup(&sblock, node.dp1.di_size)); - wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), - sblock.fs_fsize, iobuf); + node.dp1.di_dirdepth = 1; + wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), + sblock.fs_fsize, iobuf); iput(&node, UFS_ROOTINO + 1); } } else { @@ -948,8 +981,9 @@ fsinit(time_t utime) alloc(sblock.fs_fsize, node.dp2.di_mode); node.dp2.di_blocks = btodb(fragroundup(&sblock, node.dp2.di_size)); - wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), - sblock.fs_fsize, iobuf); + node.dp2.di_dirdepth = 1; + wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), + sblock.fs_fsize, iobuf); iput(&node, UFS_ROOTINO + 1); } } @@ -1188,7 +1222,7 @@ ilog2(int val) static u_int32_t newfs_random(void) { - static int nextnum = 1; + static u_int32_t nextnum = 1; if (Rflag) return (nextnum++); |