From 493024ea1d74e4cb48aac3a24111f5c8da343e9f Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Sun, 13 Jun 2010 14:00:00 -0400 Subject: [PATCH] mke2fs: Fix up the fs type and feature selection for 64-bit blocks We need to defer setting the blocks count field in the fs_param structure until it is known whether 64-bit feature will be enabled (and whether the blocks count is valid). We also add a new mke2fs.conf configuration parameter, auto_64-bit_support which will automatically enable the 64-bit feature if the number of blocks requires it. Signed-off-by: "Theodore Ts'o" --- misc/mke2fs.c | 112 ++++++++++++++++++++++++-------------------------- misc/mke2fs.conf | 1 + misc/mke2fs.conf.5.in | 8 ++++ 3 files changed, 63 insertions(+), 58 deletions(-) diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 2840b91..add7c0c 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -66,6 +66,8 @@ extern int optind; #define STRIDE_LENGTH 8 +#define MAX_32_NUM ((((unsigned long long) 1) << 32) - 1) + #ifndef __sparc__ #define ZAP_BOOTBLOCK #endif @@ -876,6 +878,7 @@ static void print_str_list(char **list) static char **parse_fs_type(const char *fs_type, const char *usage_types, struct ext2_super_block *fs_param, + blk64_t fs_blocks_count, char *progname) { const char *ext_type = 0; @@ -884,7 +887,7 @@ static char **parse_fs_type(const char *fs_type, char *cp, *t; const char *size_type; struct str_list list; - unsigned long meg; + unsigned long long meg; int is_hurd = 0; if (init_list(&list)) @@ -938,10 +941,14 @@ static char **parse_fs_type(const char *fs_type, } meg = (1024 * 1024) / EXT2_BLOCK_SIZE(fs_param); - if (ext2fs_blocks_count(fs_param) < 3 * meg) + if (fs_blocks_count < 3 * meg) size_type = "floppy"; - else if (ext2fs_blocks_count(fs_param) < 512 * meg) + else if (fs_blocks_count < 512 * meg) size_type = "small"; + else if (fs_blocks_count >= 4 * 1024 * 1024 * meg) + size_type = "big"; + else if (fs_blocks_count >= 16 * 1024 * 1024 * meg) + size_type = "huge"; else size_type = "default"; @@ -1085,6 +1092,7 @@ static void PRS(int argc, char *argv[]) const char * fs_type = 0; const char * usage_types = 0; blk64_t dev_size; + blk64_t fs_blocks_count = 0; #ifdef __linux__ struct utsname ut; #endif @@ -1404,9 +1412,9 @@ static void PRS(int argc, char *argv[]) blocksize, sys_page_size); } if (optind < argc) { - ext2fs_blocks_count_set(&fs_param, parse_num_blocks2(argv[optind++], - fs_param.s_log_block_size)); - if (!ext2fs_blocks_count(&fs_param)) { + fs_blocks_count = parse_num_blocks2(argv[optind++], + fs_param.s_log_block_size); + if (!fs_blocks_count) { com_err(program_name, 0, _("invalid blocks count - %s"), argv[optind - 1]); exit(1); @@ -1421,7 +1429,8 @@ static void PRS(int argc, char *argv[]) fs_param.s_log_frag_size = fs_param.s_log_block_size; - fs_types = parse_fs_type(fs_type, usage_types, &fs_param, argv[0]); + fs_types = parse_fs_type(fs_type, usage_types, &fs_param, fs_blocks_count, + argv[0]); if (!fs_types) { fprintf(stderr, _("Failed to parse fs types list\n")); exit(1); @@ -1453,56 +1462,20 @@ static void PRS(int argc, char *argv[]) if (tmp) free(tmp); - if (noaction && ext2fs_blocks_count(&fs_param)) { - dev_size = ext2fs_blocks_count(&fs_param); + if (noaction && fs_blocks_count) { + dev_size = fs_blocks_count; retval = 0; - } else { - retry: + } else retval = ext2fs_get_device_size2(device_name, EXT2_BLOCK_SIZE(&fs_param), &dev_size); - if (!(fs_param.s_feature_incompat & - EXT4_FEATURE_INCOMPAT_64BIT) && dev_size >= (1ULL << 32)) - retval = EFBIG; - - if ((retval == EFBIG) && - (blocksize == 0) && - (fs_param.s_log_block_size == 0)) { - fs_param.s_log_block_size = 2; - blocksize = 4096; - goto retry; - } - } - if (retval == EFBIG) { - blk64_t big_dev_size; - - if (blocksize < 4096) { - fs_param.s_log_block_size = 2; - blocksize = 4096; - } - retval = ext2fs_get_device_size2(device_name, - EXT2_BLOCK_SIZE(&fs_param), &big_dev_size); - if (retval) - goto get_size_failure; - if (big_dev_size == (1ULL << 32)) { - dev_size = (blk_t) (big_dev_size - 1); - goto got_size; - } - fprintf(stderr, _("%s: Size of device %s too big " - "to be expressed in 32 bits\n\t" - "using a blocksize of %d.\n"), - program_name, device_name, EXT2_BLOCK_SIZE(&fs_param)); - exit(1); - } -get_size_failure: if (retval && (retval != EXT2_ET_UNIMPLEMENTED)) { com_err(program_name, retval, _("while trying to determine filesystem size")); exit(1); } -got_size: - if (!ext2fs_blocks_count(&fs_param)) { + if (!fs_blocks_count) { if (retval == EXT2_ET_UNIMPLEMENTED) { com_err(program_name, 0, _("Couldn't determine device size; you " @@ -1522,21 +1495,44 @@ got_size: )); exit(1); } - ext2fs_blocks_count_set(&fs_param, dev_size); - if (sys_page_size > EXT2_BLOCK_SIZE(&fs_param)) { - blk64_t tmp = ext2fs_blocks_count(&fs_param); - - tmp &= ~((blk64_t) ((sys_page_size / + fs_blocks_count = dev_size; + if (sys_page_size > EXT2_BLOCK_SIZE(&fs_param)) + fs_blocks_count &= ~((blk64_t) ((sys_page_size / EXT2_BLOCK_SIZE(&fs_param))-1)); - ext2fs_blocks_count_set(&fs_param, tmp); - } } - } else if (!force && (ext2fs_blocks_count(&fs_param) > dev_size)) { + } else if (!force && (fs_blocks_count > dev_size)) { com_err(program_name, 0, _("Filesystem larger than apparent device size.")); proceed_question(); } + /* + * We now need to do a sanity check of fs_blocks_count for + * 32-bit vs 64-bit block number support. + */ + if ((fs_blocks_count > MAX_32_NUM) && (blocksize == 0)) { + fs_blocks_count /= 4; /* Try using a 4k blocksize */ + blocksize = 4096; + fs_param.s_log_block_size = 2; + } + if ((fs_blocks_count > MAX_32_NUM) && + !(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) && + get_bool_from_profile(fs_types, "auto_64-bit_support", 0)) { + fs_param.s_feature_incompat |= EXT4_FEATURE_INCOMPAT_64BIT; + fs_param.s_feature_compat &= ~EXT2_FEATURE_COMPAT_RESIZE_INODE; + } + if ((fs_blocks_count > MAX_32_NUM) && + !(fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT)) { + fprintf(stderr, _("%s: Size of device (0x%llx blocks) %s " + "too big to be expressed\n\t" + "in 32 bits using a blocksize of %d.\n"), + program_name, fs_blocks_count, device_name, + EXT2_BLOCK_SIZE(&fs_param)); + exit(1); + } + + ext2fs_blocks_count_set(&fs_param, fs_blocks_count); + if (fs_param.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { fs_types[0] = strdup("journal"); fs_types[1] = 0; @@ -1747,10 +1743,10 @@ got_size: if (num_inodes == 0) { unsigned long long n; n = ext2fs_blocks_count(&fs_param) * blocksize / inode_ratio; - if (n > ~0U) { + if (n > MAX_32_NUM) { if (fs_param.s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) - num_inodes = ~0U; + num_inodes = MAX_32_NUM; else { com_err(program_name, 0, _("too many inodes (%llu), raise" @@ -1758,7 +1754,7 @@ got_size: exit(1); } } - } else if (num_inodes > ~0U) { + } else if (num_inodes > MAX_32_NUM) { com_err(program_name, 0, _("too many inodes (%llu), specify < 2^32 inodes"), num_inodes); diff --git a/misc/mke2fs.conf b/misc/mke2fs.conf index 52fe58e..a7dd1c7 100644 --- a/misc/mke2fs.conf +++ b/misc/mke2fs.conf @@ -10,6 +10,7 @@ } ext4 = { features = has_journal,extent,huge_file,flex_bg,uninit_bg,dir_nlink,extra_isize + auto_64-bit_support = 1 inode_size = 256 } ext4dev = { diff --git a/misc/mke2fs.conf.5.in b/misc/mke2fs.conf.5.in index c1b54f7..d212947 100644 --- a/misc/mke2fs.conf.5.in +++ b/misc/mke2fs.conf.5.in @@ -303,6 +303,14 @@ relations. It may be overridden by the command-line option to .BR mke2fs (8). .TP +.I auto_64-bit_support +This relation is a boolean which specifies whether +.BR mke2fs (8) +should automatically add the 64bit feature if the number of blocks for +the file system requires this feature to be enabled. The resize_inode +feature is also automatically disabled since it doesn't support 64-bit +block numbers. +.TP .I blocksize This relation specifies the default blocksize if the user does not specify a blocksize on the command line. -- 1.8.3.1