ffs: restore backward compatibility of newfs and makefs with older binaries

The previous change to CGSIZE had the unintended side-effect of allowing
newfs and makefs to create file systems that would fail validation when
examined by older commands and kernels, by allowing newfs/makefs to pack
slightly more blocks into a CG than those older binaries think is valid.
Fix this by having newfs/makefs artificially restrict the number of blocks
in a CG to the slightly smaller value that those older binaries will accept.
The validation code will continue to accept the slightly larger value
that the current newfs/makefs (before this change) could create.

Fixes:		0a6e34e950
Reviewed by:	mckusick
MFC after:	3 days
Sponsored by:	Netflix
This commit is contained in:
Chuck Silvers 2023-05-29 19:26:28 -07:00
parent 8164032a49
commit d464a7698d
2 changed files with 46 additions and 6 deletions

View File

@ -76,6 +76,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
@ -369,7 +386,8 @@ mkfs(struct partition *pp, char *fsys)
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;
}
@ -388,9 +406,11 @@ mkfs(struct partition *pp, char *fsys)
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;

View File

@ -80,6 +80,23 @@ static int count_digits(int);
#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 union {
struct fs fs;
char pad[SBLOCKSIZE];
@ -347,7 +364,8 @@ ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp)
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;
}
@ -366,9 +384,11 @@ ffs_mkfs(const char *fsys, const fsinfo_t *fsopts, time_t tstamp)
INOPB(&sblock));
if (sblock.fs_size / sblock.fs_fpg < 1)
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;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),