uint32_t nblocks, nblocks_full, nreserved;
uint32_t ngroups;
uint32_t bytes_per_inode;
- uint32_t first_data_block;
+ uint32_t first_block;
uint32_t inodes_per_group;
uint32_t gdtsz, itsz;
time_t timestamp;
}
// number of bits in one block, i.e. 8*blocksize
#define blocks_per_group (8 * blocksize)
- first_data_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
+ first_block = (EXT2_MIN_BLOCK_SIZE == blocksize);
blocksize_log2 = int_log2(blocksize);
// Determine number of blocks
// Note: blocksize and bytes_per_inode are never recalculated.
retry:
// N.B. a block group can have no more than blocks_per_group blocks
- ngroups = div_roundup(nblocks - first_data_block, blocks_per_group);
+ ngroups = div_roundup(nblocks - first_block, blocks_per_group);
if (0 == ngroups)
bb_error_msg_and_die("ngroups");
uint32_t rgdtsz = 0xFFFFFFFF; // maximum block number
if (nblocks < rgdtsz / 1024)
rgdtsz = nblocks * 1024;
- rgdtsz = div_roundup(rgdtsz - first_data_block, blocks_per_group);
+ rgdtsz = div_roundup(rgdtsz - first_block, blocks_per_group);
rgdtsz = div_roundup(rgdtsz, blocksize / sizeof(*gd)) - gdtsz;
if (rgdtsz > blocksize / sizeof(uint32_t))
rgdtsz = blocksize / sizeof(uint32_t);
// the last group needs more attention: isn't it too small for possible overhead?
overhead = (has_super(ngroups - 1) ? (1/*sb*/ + gdtsz) : 0) + 1/*bbmp*/ + 1/*ibmp*/ + itsz;
- remainder = (nblocks - first_data_block) % blocks_per_group;
+ remainder = (nblocks - first_block) % blocks_per_group;
if ((1 == ngroups) && remainder && (remainder < overhead))
bb_error_msg_and_die("way small device");
- if (remainder && (remainder < overhead + 50/* e2fsprogs hardcoded */)) {
+ // Standard mke2fs uses 50. Looks like a bug in our calculation
+ // of "remainder" or "overhead" - we dont match standard mke2fs
+ // when we transition from one group to two groups (a bit after 8M
+ // image size) and for two->three groups transition (at 16M) too.
+ if (remainder && (remainder < overhead + 50)) {
//bb_info_msg("CHOP[%u]", remainder);
nblocks -= remainder;
goto retry;
}
}
- // print info
if (nblocks_full - nblocks)
printf("warning: %u blocks unused\n\n", nblocks_full - nblocks);
printf(
, blocksize, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE
, inodes_per_group * ngroups, nblocks
, nreserved, reserved_percent
- , first_data_block
+ , first_block
, gdtsz * (blocksize / sizeof(*gd)) * blocks_per_group
, ngroups
, blocks_per_group, blocks_per_group
{
const char *fmt = "\nSuperblock backups stored on blocks:\n"
"\t%u";
- pos = first_data_block;
+ pos = first_block;
for (i = 1; i < ngroups; i++) {
pos += blocks_per_group;
if (has_super(i)) {
STORE_LE(sb->s_log_block_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
STORE_LE(sb->s_log_frag_size, blocksize_log2 - EXT2_MIN_BLOCK_LOG_SIZE);
// first 1024 bytes of the device are for boot record. If block size is 1024 bytes, then
- // the first block available for data is 1, otherwise 0
- STORE_LE(sb->s_first_data_block, first_data_block); // 0 or 1
+ // the first block is 1, otherwise 0
+ STORE_LE(sb->s_first_data_block, first_block);
// block and inode bitmaps occupy no more than one block, so maximum number of blocks is
STORE_LE(sb->s_blocks_per_group, blocks_per_group);
STORE_LE(sb->s_frags_per_group, blocks_per_group);
gd = xzalloc(gdtsz * blocksize);
buf = xmalloc(blocksize);
sb->s_free_blocks_count = 0;
- for (i = 0, pos = first_data_block, n = nblocks - first_data_block;
+ for (i = 0, pos = first_block, n = nblocks - first_block;
i < ngroups;
i++, pos += blocks_per_group, n -= blocks_per_group
) {
// dump filesystem skeleton structures
// printf("Writing superblocks and filesystem accounting information: ");
- for (i = 0, pos = first_data_block; i < ngroups; i++, pos += blocks_per_group) {
+ for (i = 0, pos = first_block; i < ngroups; i++, pos += blocks_per_group) {
// dump superblock and group descriptors and their backups
if (has_super(i)) {
// N.B. 1024 byte blocks are special
- PUT(((uint64_t)pos * blocksize) + ((0 == i && 0 == first_data_block) ? 1024 : 0), sb, 1024);//blocksize);
+ PUT(((uint64_t)pos * blocksize) + ((0 == i && 0 == first_block) ? 1024 : 0), sb, 1024);//blocksize);
PUT(((uint64_t)pos * blocksize) + blocksize, gd, gdtsz * blocksize);
}
}
# -:bbox +:standard
-# kilobytes=60 is the minimal allowed size.
-#
-# kilobytes=8378 is the first value where we differ from std:
-# +warning: 185 blocks unused
-# Filesystem label=
-# OS type: Linux
-# Block size=1024 (log=0)
-# Fragment size=1024 (log=0)
-# -2096 inodes, 8378 blocks
-# +2096 inodes, 8193 blocks
-# 418 blocks reserved for the super user
-# First data block=1
-# -2 block groups
-# +1 block groups
-# 8192 blocks per group, 8192 fragments per group
-# -1048 inodes per group
-# -Superblock backups stored on blocks:
-# -8193
-# +2096 inodes per group
-#
+# kilobytes=60 is the minimal allowed size
kilobytes=60
while true; do
test_mke2fs || exit 1
: $((kilobytes++))
- test $kilobytes = 300000 && break
+ test $kilobytes = 200 && break
+done
+
+# Transition from one block group to two
+# fails in [8378..8410] range
+kilobytes=$((8*1024 - 20))
+while true; do
+ test_mke2fs #|| exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((8*1024 + 300)) && break
+done
+
+# Transition from two block groups to three
+# works
+kilobytes=$((16*1024 - 40))
+while true; do
+ test_mke2fs || exit 1
+ : $((kilobytes++))
+ test $kilobytes = $((16*1024 + 500)) && break
done
exit