From bfc28c76131695283753084da306e6c73ab8b1ce Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Mon, 13 May 2019 13:41:07 +0200 Subject: [PATCH 1/6] Define {MAX_,}RESERVED_BLOCKS as floats As it was defined could not work in other contexts (the current lone use works by chance, because multiplication is done first), where the division may yield an unexpected (but valid) zero result. --- genext2fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index e963d9c..e67a4a9 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -166,8 +166,8 @@ static int blocksize = 1024; #define BLOCKS_PER_GROUP 8192 #define INODES_PER_GROUP 8192 /* Percentage of blocks that are reserved.*/ -#define RESERVED_BLOCKS 5/100 -#define MAX_RESERVED_BLOCKS 25/100 +#define RESERVED_BLOCKS (5/100.) +#define MAX_RESERVED_BLOCKS (25/100.) /* The default value for s_creator_os. */ #if defined(__linux__) && defined(EXT2_OS_LINUX) From 5b93731b33ded0769f8e633cd75b552b5ff4e73b Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Mon, 13 May 2019 13:53:58 +0200 Subject: [PATCH 2/6] Recover automatic block number calculation The total block count was once done automatically but it was lost on commit 457078c90d5a3738ee2ed2206728b1b5cacecb9f. The calculation is recovered, but made optional: it is only done if total blocks is not passed by cmdline. If passed, that value is used and not touched. Also, reserved_frac is taken into account on the automatic calculation. --- genext2fs.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index e67a4a9..f97089b 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -3343,16 +3343,30 @@ main(int argc, char **argv) } else { - if(reserved_frac == -1) - nbresrvd = nbblocks * RESERVED_BLOCKS; - else - nbresrvd = nbblocks * reserved_frac; - - stats.ninodes = EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0); + stats.ninodes = 0; stats.nblocks = 0; populate_fs(NULL, dopt, didx, squash_uids, squash_perms, fs_timestamp, &stats); + if(reserved_frac == -1) + reserved_frac = RESERVED_BLOCKS; + + if(nbblocks == -1) + { + nbblocks = stats.nblocks; + nbblocks += nbblocks * reserved_frac; + } + else + if(stats.nblocks > nbblocks) + { + // fprintf(stderr, "number of blocks too low, increasing to %ld\n", stats.nblocks); + // nbblocks = stats.nblocks; + error_msg_and_die("number of blocks too low. Need at least %d.", stats.nblocks); + } + + nbresrvd = nbblocks * reserved_frac; + stats.ninodes += EXT2_FIRST_INO - 1 + (nbresrvd ? 1 : 0); + if(nbinodes == -1) nbinodes = stats.ninodes; else From d6e659d0a9380546c6e884a2896b93bb0a1d6f64 Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Mon, 13 May 2019 15:37:48 +0200 Subject: [PATCH 3/6] Correct message for minimum block count Must take into account the reserved blocks. --- genext2fs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/genext2fs.c b/genext2fs.c index f97089b..6c241d4 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -3361,7 +3361,8 @@ main(int argc, char **argv) { // fprintf(stderr, "number of blocks too low, increasing to %ld\n", stats.nblocks); // nbblocks = stats.nblocks; - error_msg_and_die("number of blocks too low. Need at least %d.", stats.nblocks); + unsigned long minimum_blocks = stats.nblocks + stats.nblocks * reserved_frac; + error_msg_and_die("number of blocks too low. Need at least %lu.", minimum_blocks); } nbresrvd = nbblocks * reserved_frac; From 1b2a30e4c89e5dfdf64af02b9c42163cca7e674d Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Mon, 13 May 2019 15:47:29 +0200 Subject: [PATCH 4/6] Correct also commented code to take into account reserved blocks --- genext2fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index 6c241d4..e76acf8 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -3359,9 +3359,9 @@ main(int argc, char **argv) else if(stats.nblocks > nbblocks) { - // fprintf(stderr, "number of blocks too low, increasing to %ld\n", stats.nblocks); - // nbblocks = stats.nblocks; unsigned long minimum_blocks = stats.nblocks + stats.nblocks * reserved_frac; + // fprintf(stderr, "number of blocks too low, increasing to %ld\n", minimum_blocks); + // nbblocks = minimum_blocks; error_msg_and_die("number of blocks too low. Need at least %lu.", minimum_blocks); } From 944a4fde1207a85482c7665108db6f12e8b1466c Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Sun, 23 Jun 2019 15:40:10 +0200 Subject: [PATCH 5/6] Indirect blocks must be taken into account for stats Add indirect blocks to file block count stats. --- genext2fs.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 3 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index e76acf8..b72c28e 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -163,6 +163,7 @@ static int blocksize = 1024; #define SUPERBLOCK_SIZE 1024 #define BLOCKSIZE blocksize +#define ADDR_PER_BLOCK (BLOCKSIZE / sizeof(uint32)) #define BLOCKS_PER_GROUP 8192 #define INODES_PER_GROUP 8192 /* Percentage of blocks that are reserved.*/ @@ -2278,6 +2279,70 @@ add2fs_from_file(filesystem *fs, uint32 this_nod, FILE * fh, uint32 fs_timestamp free(path2); } +static long +calc_file_alloc_blocks(unsigned long size) +{ + const int double_blocks = ADDR_PER_BLOCK * ADDR_PER_BLOCK; + long file_blocks = (size + BLOCKSIZE - 1) / BLOCKSIZE; + long final_file_blocks; + + /* Total file data blocks: + * - direct blocks: EXT2_NDIR_BLOCKS + * - 1st indirect blocks: + ADDR_PER_BLOCK + * - 2nd indirect blocks: + ADDR_PER_BLOCK*ADDR_PER_BLOCK + * - 3rd indirect blocks: + ADDR_PER_BLOCK*ADDR_PER_BLOCK*ADDR_PER_BLOCK + * + * Total blocks allocated in disk: + * - direct blocks: EXT2_NDIR_BLOCKS + * - 1st indirect blocks: + (1 + ADDR_PER_BLOCK) + * - 2nd indirect blocks: + (1 + ADDR_PER_BLOCK + ADDR_PER_BLOCK*ADDR_PER_BLOCK) + * - 3rd indirect blocks: + (1 + ADDR_PER_BLOCK + ADDR_PER_BLOCK*ADDR_PER_BLOCK + ADDR_PER_BLOCK*ADDR_PER_BLOCK*ADDR_PER_BLOCK) + */ + + if(file_blocks <= EXT2_NDIR_BLOCKS) + return file_blocks; + + // All direct blocks used + file_blocks -= EXT2_NDIR_BLOCKS; + final_file_blocks = EXT2_NDIR_BLOCKS; + + // Need 1st indirection + if(file_blocks <= ADDR_PER_BLOCK) + { + // +1 indirect block + final_file_blocks += 1 + file_blocks; + return final_file_blocks; + } + + // All 1st indirect blocks used + file_blocks -= ADDR_PER_BLOCK; + final_file_blocks += 1 + ADDR_PER_BLOCK; + + // Need 2nd indirection + if(file_blocks <= double_blocks) + { + int indirect_blocks = 1 + (file_blocks + ADDR_PER_BLOCK - 1) / ADDR_PER_BLOCK; + final_file_blocks += file_blocks + indirect_blocks; + return final_file_blocks; + } + + // All 2nd indirect blocks used + file_blocks -= double_blocks; + final_file_blocks += 1 + double_blocks; + + // Need 2rd indirection + if(file_blocks / double_blocks <= ADDR_PER_BLOCK) + { + //(1 + ADDR_PER_BLOCK + ADDR_PER_BLOCK*ADDR_PER_BLOCK + ADDR_PER_BLOCK*ADDR_PER_BLOCK*ADDR_PER_BLOCK) + int indirect_blocks = 1 + (file_blocks + double_blocks - 1) / double_blocks + + (file_blocks + ADDR_PER_BLOCK - 1) / ADDR_PER_BLOCK; + final_file_blocks += file_blocks + indirect_blocks; + return final_file_blocks; + } + + return -1; +} + // adds a tree of entries to the filesystem from current dir static void add2fs_from_dir(filesystem *fs, uint32 this_nod, int squash_uids, int squash_perms, uint32 fs_timestamp, struct stats *stats) @@ -2318,8 +2383,14 @@ add2fs_from_dir(filesystem *fs, uint32 this_nod, int squash_uids, int squash_per stats->ninodes++; break; case S_IFREG: - if((st.st_mode & S_IFMT) == S_IFREG || st.st_size > 4 * (EXT2_TIND_BLOCK+1)) - stats->nblocks += (st.st_size + BLOCKSIZE - 1) / BLOCKSIZE; + { + int total_blocks = calc_file_alloc_blocks(st.st_size); + if(total_blocks == -1) + error_msg_and_die("%s: file too large", dent->d_name); + stats->nblocks += total_blocks; + fprintf(stderr, "Large file: %lu final blocks\n", total_blocks); + // Fall through + } case S_IFCHR: case S_IFBLK: case S_IFIFO: @@ -3353,7 +3424,12 @@ main(int argc, char **argv) if(nbblocks == -1) { - nbblocks = stats.nblocks; + /* On filesystems with 1k block size, the bootloader area uses a full + * block. For 2048 and up, the superblock can be fitted into block 0. + */ + int first_block = (BLOCKSIZE == 1024); + /* bootloader block + superblock + data blocks */ + nbblocks = 1 + first_block + stats.nblocks; nbblocks += nbblocks * reserved_frac; } else From 3e2fce11832bef7a783f596f4c44d469cfc07146 Mon Sep 17 00:00:00 2001 From: Xabier Oneca Date: Mon, 6 Jul 2020 01:33:06 +0200 Subject: [PATCH 6/6] Restore (MAX_)RESERVED_BLOCKS to integer division Leave the two constants as were defined originally. This reverts the changes made by commit bfc28c76131695283753084da306e6c73ab8b1ce. --- genext2fs.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/genext2fs.c b/genext2fs.c index b72c28e..a78bb42 100644 --- a/genext2fs.c +++ b/genext2fs.c @@ -167,8 +167,8 @@ static int blocksize = 1024; #define BLOCKS_PER_GROUP 8192 #define INODES_PER_GROUP 8192 /* Percentage of blocks that are reserved.*/ -#define RESERVED_BLOCKS (5/100.) -#define MAX_RESERVED_BLOCKS (25/100.) +#define RESERVED_BLOCKS 5/100 +#define MAX_RESERVED_BLOCKS 25/100 /* The default value for s_creator_os. */ #if defined(__linux__) && defined(EXT2_OS_LINUX) @@ -3420,7 +3420,7 @@ main(int argc, char **argv) populate_fs(NULL, dopt, didx, squash_uids, squash_perms, fs_timestamp, &stats); if(reserved_frac == -1) - reserved_frac = RESERVED_BLOCKS; + reserved_frac = 1.0 * RESERVED_BLOCKS; if(nbblocks == -1) {