Rework of code that sorts out number of cylinder groups and inodes:

- allows less than 'one fragment per inode' (useful for mfs /dev)
- limits number of inodes to 2^31 (they are stored in an int32_t)
- errors if the number of cylinder groups is such that the cylinder group
  summary won't fit in the first cylinder group.
- ensures that the last cylinder block contains a valid number of fragments
  and inodes, and is not larger than any earlier ones.
- cylinder groups are now created with almost the same size as each other.
Change posted to tech-kern, and no one objected.
This commit is contained in:
dsl 2003-08-21 14:55:03 +00:00
parent 6196bbe72d
commit cff5fdb06e
1 changed files with 98 additions and 79 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: mkfs.c,v 1.73 2003/08/15 15:24:21 dsl Exp $ */
/* $NetBSD: mkfs.c,v 1.74 2003/08/21 14:55:03 dsl Exp $ */
/*
* Copyright (c) 1980, 1989, 1993
@ -73,7 +73,7 @@
#if 0
static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95";
#else
__RCSID("$NetBSD: mkfs.c,v 1.73 2003/08/15 15:24:21 dsl Exp $");
__RCSID("$NetBSD: mkfs.c,v 1.74 2003/08/21 14:55:03 dsl Exp $");
#endif
#endif /* not lint */
@ -162,7 +162,9 @@ void
mkfs(struct partition *pp, const char *fsys, int fi, int fo,
mode_t mfsmode, uid_t mfsuid, gid_t mfsgid)
{
int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg;
uint fragsperinodeblk, ncg;
uint cgzero;
uint64_t inodeblks, cgall;
int32_t cylno, i, csfrags;
struct timeval tv;
long long sizepb;
@ -295,7 +297,7 @@ mkfs(struct partition *pp, const char *fsys, int fi, int fo,
exit(21);
}
sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize);
sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
sblock.fs_size = dbtofsb(&sblock, fssize);
if (Oflag <= 1) {
if (sblock.fs_size >= 1ull << 31) {
printf("Too many fragments (0x%" PRIx64
@ -345,87 +347,104 @@ mkfs(struct partition *pp, const char *fsys, int fi, int fo,
/*
* Calculate the number of blocks to put into each cylinder group.
*
* This algorithm selects the number of blocks per cylinder
* group. The first goal is to have at least enough data blocks
* in each cylinder group to meet the density requirement. Once
* this goal is achieved we try to expand to have at least
* MINCYLGRPS cylinder groups. Once this goal is achieved, we
* pack as many blocks into each cylinder group map as will fit.
* The cylinder group size is limited because the data structure
* must fit into a single block.
* We try to have as few cylinder groups as possible, with a proviso
* that we create at least MINCYLGRPS (==4) except for small
* filesystems.
*
* We start by calculating the smallest number of blocks that we
* can put into each cylinder group. If this is too big, we reduce
* the density until it fits.
* This algorithm works out how many blocks of inodes would be
* needed to fill the entire volume at the specified density.
* It then looks at how big the 'cylinder block' would have to
* be and, assuming that it is linearly related to the number
* of inodes and blocks how many cylinder groups are needed to
* keep the cylinder block below the filesystem block size.
*
* The cylinder groups are then all created with the average size.
*
* Space taken by the red tape on cylinder groups other than the
* first is ignored.
*/
origdensity = density;
for (;;) {
fragsperinode = MAX(numfrags(&sblock, density), 1);
minfpg = fragsperinode * INOPB(&sblock);
if (minfpg > sblock.fs_size)
minfpg = sblock.fs_size;
sblock.fs_ipg = INOPB(&sblock);
sblock.fs_fpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_fpg < minfpg)
sblock.fs_fpg = minfpg;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
sblock.fs_fpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_fpg < minfpg)
sblock.fs_fpg = minfpg;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
break;
density -= sblock.fs_fsize;
}
if (density != origdensity)
printf("density reduced from %d to %d\n", origdensity, density);
/*
* Start packing more blocks into the cylinder group until
* it cannot grow any larger, the number of cylinder groups
* drops below MINCYLGRPS, or we reach the size requested.
*/
for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) {
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
if (sblock.fs_size / sblock.fs_fpg < MINCYLGRPS)
break;
if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
continue;
if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize)
break;
sblock.fs_fpg -= sblock.fs_frag;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
break;
/* There must be space for 1 inode block and 2 data blocks */
if (sblock.fs_size < sblock.fs_iblkno + 3 * sblock.fs_frag) {
printf("Filesystem size %lld < minimum size of %d\n",
(long long)sblock.fs_size, sblock.fs_iblkno + 3 * sblock.fs_frag);
exit(23);
}
/*
* Check to be sure that the last cylinder group has enough blocks
* to be viable. If it is too small, reduce the number of blocks
* per cylinder group which will have the effect of moving more
* blocks into the last cylinder group.
* Calculate 'per inode block' so we can allocate less than 1 fragment
* per inode - useful for /dev.
*/
optimalfpg = sblock.fs_fpg;
for (;;) {
sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
lastminfpg = roundup(sblock.fs_iblkno +
sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
if (sblock.fs_size < lastminfpg) {
printf("Filesystem size %lld < minimum size of %d\n",
(long long)sblock.fs_size, lastminfpg);
exit(28);
}
if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
sblock.fs_size % sblock.fs_fpg == 0)
break;
sblock.fs_fpg -= sblock.fs_frag;
sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
INOPB(&sblock));
fragsperinodeblk = MAX(numfrags(&sblock, density * INOPB(&sblock)), 1);
inodeblks = (sblock.fs_size - sblock.fs_iblkno - 2 * sblock.fs_frag) /
(sblock.fs_frag + fragsperinodeblk);
if (inodeblks == 0)
inodeblks = 1;
/* Even UFS2 limits number of inodes to 2^31 (fs_ipg is int32_t) */
if (inodeblks * INOPB(&sblock) >= 1ull << 31)
inodeblks = ((1ull << 31) - NBBY) / INOPB(&sblock);
/*
* See what would happen if we tried to use 1 cylinder group.
* Assume space linear, so work out number of cylinder groups needed.
* Subtract one from the allowed size to compensate for rounding
* a number of bits up to a complete byte.
*/
cgzero = CGSIZE_IF(&sblock, 0, 0);
cgall = CGSIZE_IF(&sblock, inodeblks * INOPB(&sblock), sblock.fs_size);
ncg = howmany(cgall - cgzero, sblock.fs_bsize - cgzero - 1);
if (ncg < MINCYLGRPS) {
/*
* We would like to allocate MINCLYGRPS cylinder groups,
* but for small file sytems (especially ones with a lot
* of inodes) this is not desirable (or possible).
*/
i = sblock.fs_size / 2 / (sblock.fs_iblkno +
inodeblks * sblock.fs_frag);
if (i > ncg)
ncg = i;
if (ncg > MINCYLGRPS)
ncg = MINCYLGRPS;
if (ncg > inodeblks)
ncg = inodeblks;
}
if (optimalfpg != sblock.fs_fpg)
printf("Reduced frags per cylinder group from %d to %d %s\n",
optimalfpg, sblock.fs_fpg, "to enlarge last cyl group");
/*
* Put an equal number of blocks in each cylinder group.
* Round up so we don't have more fragments in the last CG than
* the earlier ones (does that matter?), but kill a block if the
* CGSIZE becomes too big (only happens if there are a lot of CGs).
*/
sblock.fs_fpg = roundup(howmany(sblock.fs_size, ncg), sblock.fs_frag);
i = CGSIZE_IF(&sblock, inodeblks * INOPB(&sblock) / ncg, sblock.fs_fpg);
if (i > sblock.fs_bsize)
sblock.fs_fpg -= (i - sblock.fs_bsize) * NBBY;
/* ... and recalculate how many cylinder groups we now need */
ncg = howmany(sblock.fs_size, sblock.fs_fpg);
inodeblks /= ncg;
if (inodeblks == 0)
inodeblks = 1;
sblock.fs_ipg = inodeblks * INOPB(&sblock);
/* Sanity check on our sums... */
if (CGSIZE(&sblock) > sblock.fs_bsize) {
printf("CGSIZE miscalculated %d > %d\n",
(int)CGSIZE(&sblock), sblock.fs_bsize);
exit(24);
}
/* Check that the last cylinder group has enough space for the inodes */
i = sblock.fs_size - sblock.fs_fpg * (ncg - 1ull);
if (i < sblock.fs_iblkno + inodeblks * sblock.fs_frag) {
/*
* Since we make all the cylinder groups the same size, the
* last will only be small if there are a large number of
* cylinder groups. If we pull even a fragment from each
* of the other groups then the last CG will be overfull.
* So we just kill the last CG.
*/
ncg--;
sblock.fs_size -= i;
}
sblock.fs_ncg = ncg;
sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
if (Oflag <= 1) {