From: Theodore Ts'o Subject: [PATCH, RFC 00/12] bigalloc patchset Date: Sat, 19 Mar 2011 17:28:25 -0400 Message-ID: <1300570117-24048-1-git-send-email-tytso@mit.edu> Cc: Theodore Ts'o To: linux-ext4@vger.kernel.org Return-path: Received: from li9-11.members.linode.com ([67.18.176.11]:42968 "EHLO test.thunk.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757564Ab1CSV2j (ORCPT ); Sat, 19 Mar 2011 17:28:39 -0400 Sender: linux-ext4-owner@vger.kernel.org List-ID: This is an initial patchset of the bigalloc patches to ext4. This patch adds support for clustered allocation, so that each bit in the ext4 block allocation bitmap addresses a power of two number of blocks. For example, if the file system is mainly going to be storing large files in the 4-32 megabyte range, it might make sense to set a cluster size of 1 megabyte. This means that each bit in the block allocaiton bitmap would now address 256 4k blocks, and it means that the size of the block bitmaps for a 2T file system shrinks from 64 megabytes to 256k. It also means that a block group addresses 32 gigabytes instead of 128 megabytes, also shrinking the amount of file system overhead for metadata. The cost is increased disk space efficiency. Directories will consume 1T, as will extent tree blocks. (I am on the fence as to whether I should add complexity so that in the rare case that an inode needs more than 344 extents --- a highly fragmented file indeed --- and need a second extent tree block, we can avoid allocating any cluster and instead use another block from the cluster used by the inode. The concern is the amount of complexity this adds to the e2fsck, not just to the kernel.) To test these patches, I have used an *extremely* kludgy set of patches to e2fsprogs, which are attached below. These patches need *extensive* revision before I would consider them clean enough suitable for committing into e2fsprogs, but they were sufficient for me to do the kernel-side changes --- mke2fs, dumpe2fs, and debugfs work. E2fsck most definitely does _not_ work at this stage. Please comment! I do not intend for these patches to be merged during the 2.6.39 merge window. I am targetting 2.6.40, 3 months from now, since these patches are quite extensive. - Ted Theodore Ts'o (12): ext4: read-only support for bigalloc file systems ext4: enforce bigalloc restrictions (e.g., no online resizing, etc.) ext4: Convert instances of EXT4_BLOCKS_PER_GROUP to EXT4_CLUSTERS_PER_GROUP ext4: Remove block bitmap initialization in ext4_new_inode() ext4: factor out block group accounting into functions ext4: split out ext4_free_blocks_after_init() ext4: bigalloc changes to block bitmap initialization functions ext4: Convert block group-relative offsets to use clusters ext4: teach ext4_ext_map_blocks() about the bigalloc feature ext4: teach ext4_statfs() to deal with clusters if bigalloc is enabled ext4: tune mballoc's default group prealloc size for bigalloc file systems ext4: enable mounting bigalloc as read/write fs/ext4/balloc.c | 268 +++++++++++++++++++++++++++++++++-------------------- fs/ext4/ext4.h | 47 ++++++++-- fs/ext4/extents.c | 132 +++++++++++++++++++++++--- fs/ext4/ialloc.c | 37 -------- fs/ext4/inode.c | 7 ++ fs/ext4/ioctl.c | 33 ++++++- fs/ext4/mballoc.c | 49 ++++++---- fs/ext4/mballoc.h | 3 +- fs/ext4/super.c | 100 ++++++++++++++++---- 9 files changed, 472 insertions(+), 204 deletions(-) -- 1.7.3.1 ------------------- e2fsprogs patches follow below diff --git a/lib/ext2fs/bmap64.h b/lib/ext2fs/bmap64.h index b0aa84c..cfbdfd6 100644 --- a/lib/ext2fs/bmap64.h +++ b/lib/ext2fs/bmap64.h @@ -31,6 +31,10 @@ struct ext2fs_struct_generic_bitmap { ((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \ ((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64)) +/* Bitmap flags */ + +#define EXT2_BMFLAG_CLUSTER 0x0001 + struct ext2_bitmap_ops { int type; /* Generic bmap operators */ diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h index a89e33b..0970506 100644 --- a/lib/ext2fs/ext2_fs.h +++ b/lib/ext2fs/ext2_fs.h @@ -228,9 +228,13 @@ struct ext2_dx_countlimit { #define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group) #define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group) +#define EXT2_CLUSTERS_PER_GROUP(s) (EXT2_SB(s)->s_clusters_per_group) #define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s)) /* limits imposed by 16-bit value gd_free_{blocks,inode}_count */ -#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8) +#define EXT2_MAX_BLOCKS_PER_GROUP(s) (((1 << 16) - 8) * \ + (EXT2_CLUSTER_SIZE(s) / \ + EXT2_BLOCK_SIZE(s))) +#define EXT2_MAX_CLUSTERS_PER_GROUP(s) ((1 << 16) - 8) #define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s)) #ifdef __KERNEL__ #define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block) diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index d3eb31d..a065e87 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -207,7 +207,7 @@ struct struct_ext2_filsys { char * device_name; struct ext2_super_block * super; unsigned int blocksize; - int clustersize; + int cluster_ratio; dgrp_t group_desc_count; unsigned long desc_blocks; struct opaque_ext2_group_desc * group_desc; @@ -232,7 +232,8 @@ struct struct_ext2_filsys { /* * Reserved for future expansion */ - __u32 reserved[7]; + __u32 clustersize; + __u32 reserved[6]; /* * Reserved for the use of the calling application. @@ -553,7 +554,8 @@ typedef struct ext2_icount *ext2_icount_t; EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ - EXT4_FEATURE_RO_COMPAT_GDT_CSUM) + EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ + EXT4_FEATURE_RO_COMPAT_BIGALLOC) /* * These features are only allowed if EXT2_FLAG_SOFTSUPP_FEATURES is passed diff --git a/lib/ext2fs/gen_bitmap64.c b/lib/ext2fs/gen_bitmap64.c index df095ac..60321df 100644 --- a/lib/ext2fs/gen_bitmap64.c +++ b/lib/ext2fs/gen_bitmap64.c @@ -559,3 +559,85 @@ int ext2fs_warn_bitmap32(ext2fs_generic_bitmap bitmap, const char *func) "called %s with 64-bit bitmap", func); #endif } + +errcode_t ext2fs_allocate_cluster_bitmap(ext2_filsys fs, + const char *descr, + ext2fs_block_bitmap *ret) +{ + __u64 start, end, real_end; + errcode_t retval; + + EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + + if (!(fs->flags & EXT2_FLAG_64BITS)) + return EXT2_ET_CANT_USE_LEGACY_BITMAPS; + + fs->write_bitmaps = ext2fs_write_bitmaps; + + start = (fs->super->s_first_data_block >> + EXT2_CLUSTER_SIZE_BITS(fs->super)); + end = (ext2fs_blocks_count(fs->super) - 1) / fs->cluster_ratio; + real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super) + * (__u64) fs->group_desc_count)-1 + start; + + retval = ext2fs_alloc_generic_bmap(fs, + EXT2_ET_MAGIC_BLOCK_BITMAP64, + EXT2FS_BMAP64_BITARRAY, + start, end, real_end, descr, ret); + if (retval) + return retval; + + (*ret)->flags = EXT2_BMFLAG_CLUSTER; + + printf("Returning 0...\n"); + return 0; +} + +int ext2fs_is_cluster_bitmap(ext2fs_block_bitmap bm) +{ + if (EXT2FS_IS_32_BITMAP(bm)) + return 0; + + return (bm->flags & EXT2_BMFLAG_CLUSTER); +} + +errcode_t ext2fs_convert_to_cluster_bitmap(ext2_filsys fs, + ext2fs_block_bitmap bmap, + ext2fs_block_bitmap *ret) +{ + ext2fs_block_bitmap cmap; + errcode_t retval; + blk64_t i, j, b_end, c_end; + int n; + + retval = ext2fs_allocate_cluster_bitmap(fs, "converted cluster bitmap", + ret); + if (retval) + return retval; + + cmap = *ret; + i = bmap->start; + b_end = bmap->end; + bmap->end = bmap->real_end; + j = cmap->start; + c_end = cmap->end; + cmap->end = cmap->real_end; + n = 0; + while (i < bmap->real_end) { + if (ext2fs_test_block_bitmap2(bmap, i)) { + ext2fs_mark_block_bitmap2(cmap, j); + i += fs->cluster_ratio - n; + j++; + n = 0; + continue; + } + i++; n++; + if (n >= fs->cluster_ratio) { + j++; + n = 0; + } + } + bmap->end = b_end; + cmap->end = c_end; + return 0; +} diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c index e1f229b..00a8b38 100644 --- a/lib/ext2fs/initialize.c +++ b/lib/ext2fs/initialize.c @@ -94,6 +94,7 @@ errcode_t ext2fs_initialize(const char *name, int flags, blk_t numblocks; int rsv_gdt; int csum_flag; + int bigalloc_flag; int io_flags; char *buf = 0; char c; @@ -134,12 +135,25 @@ errcode_t ext2fs_initialize(const char *name, int flags, #define set_field(field, default) (super->field = param->field ? \ param->field : (default)) +#define assign_field(field) (super->field = param->field) super->s_magic = EXT2_SUPER_MAGIC; super->s_state = EXT2_VALID_FS; - set_field(s_log_block_size, 0); /* default blocksize: 1024 bytes */ - set_field(s_log_cluster_size, 0); + bigalloc_flag = EXT2_HAS_RO_COMPAT_FEATURE(param, + EXT4_FEATURE_RO_COMPAT_BIGALLOC); + + assign_field(s_log_block_size); + + if (bigalloc_flag) { + set_field(s_log_cluster_size, super->s_log_block_size+4); + if (super->s_log_block_size > super->s_log_cluster_size) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + } else + super->s_log_cluster_size = super->s_log_block_size; + set_field(s_first_data_block, super->s_log_block_size ? 0 : 1); set_field(s_max_mnt_count, 0); set_field(s_errors, EXT2_ERRORS_DEFAULT); @@ -183,14 +197,36 @@ errcode_t ext2fs_initialize(const char *name, int flags, fs->blocksize = EXT2_BLOCK_SIZE(super); fs->clustersize = EXT2_CLUSTER_SIZE(super); + fs->cluster_ratio = fs->clustersize / fs->blocksize; + + if (bigalloc_flag) { + if (param->s_blocks_per_group && + param->s_clusters_per_group && + ((param->s_clusters_per_group * fs->cluster_ratio) != + param->s_blocks_per_group)) { + retval = EXT2_ET_INVALID_ARGUMENT; + goto cleanup; + } + if (param->s_clusters_per_group) + assign_field(s_clusters_per_group); + else if (param->s_blocks_per_group) + super->s_clusters_per_group = + param->s_blocks_per_group / fs->cluster_ratio; + else + super->s_clusters_per_group = fs->blocksize * 8; + if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super)) + super->s_blocks_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super); + super->s_blocks_per_group = super->s_clusters_per_group; + super->s_blocks_per_group *= fs->cluster_ratio; + } else { + set_field(s_blocks_per_group, fs->blocksize * 8); + if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super)) + super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super); + super->s_clusters_per_group = super->s_blocks_per_group; + } - /* default: (fs->blocksize*8) blocks/group, up to 2^16 (GDT limit) */ - set_field(s_blocks_per_group, fs->blocksize * 8); - if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super)) - super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super); - super->s_clusters_per_group = super->s_blocks_per_group; - - ext2fs_blocks_count_set(super, ext2fs_blocks_count(param)); + ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) & + ~((blk64_t) fs->cluster_ratio - 1)); ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param)); if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) { retval = EXT2_ET_INVALID_ARGUMENT; @@ -246,7 +282,7 @@ retry: */ ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count); if (ipg > fs->blocksize * 8) { - if (super->s_blocks_per_group >= 256) { + if (!bigalloc_flag && super->s_blocks_per_group >= 256) { /* Try again with slightly different parameters */ super->s_blocks_per_group -= 8; ext2fs_blocks_count_set(super, diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c index 90abed1..8b37852 100644 --- a/lib/ext2fs/openfs.c +++ b/lib/ext2fs/openfs.c @@ -251,6 +251,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, goto cleanup; } fs->clustersize = EXT2_CLUSTER_SIZE(fs->super); + fs->cluster_ratio = fs->clustersize / fs->blocksize; fs->inode_blocks_per_group = ((EXT2_INODES_PER_GROUP(fs->super) * EXT2_INODE_SIZE(fs->super) + EXT2_BLOCK_SIZE(fs->super) - 1) / diff --git a/lib/ext2fs/rw_bitmaps.c b/lib/ext2fs/rw_bitmaps.c index 3031b7d..aeea997 100644 --- a/lib/ext2fs/rw_bitmaps.c +++ b/lib/ext2fs/rw_bitmaps.c @@ -51,7 +51,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) inode_nbytes = block_nbytes = 0; if (do_block) { - block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; + block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; retval = ext2fs_get_memalign(fs->blocksize, fs->blocksize, &block_buf); if (retval) @@ -85,7 +85,7 @@ static errcode_t write_bitmaps(ext2_filsys fs, int do_inode, int do_block) /* Force bitmap padding for the last group */ nbits = ((ext2fs_blocks_count(fs->super) - (__u64) fs->super->s_first_data_block) - % (__u64) EXT2_BLOCKS_PER_GROUP(fs->super)); + % (__u64) EXT2_CLUSTERS_PER_GROUP(fs->super)); if (nbits) for (j = nbits; j < fs->blocksize * 8; j++) ext2fs_set_bit(j, block_buf); @@ -141,7 +141,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) char *block_bitmap = 0, *inode_bitmap = 0; char *buf; errcode_t retval; - int block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; + int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; int csum_flag = 0; int do_image = fs->flags & EXT2_FLAG_IMAGE_FILE; @@ -219,7 +219,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) } blk = (fs->image_header->offset_blockmap / fs->blocksize); - blk_cnt = (blk64_t)EXT2_BLOCKS_PER_GROUP(fs->super) * + blk_cnt = (blk64_t)EXT2_CLUSTERS_PER_GROUP(fs->super) * fs->group_desc_count; while (block_nbytes > 0) { retval = io_channel_read_blk64(fs->image_io, blk++, diff --git a/misc/dumpe2fs.c b/misc/dumpe2fs.c index c01ffe5..d3f617a 100644 --- a/misc/dumpe2fs.c +++ b/misc/dumpe2fs.c @@ -71,25 +71,26 @@ static void print_range(unsigned long long a, unsigned long long b) printf("%llu-%llu", a, b); } -static void print_free (unsigned long group, char * bitmap, - unsigned long nbytes, unsigned long offset) +static void print_free(unsigned long group, char * bitmap, + unsigned long nbytes, unsigned long offset, int ratio) { int p = 0; unsigned long i; unsigned long j; + offset /= ratio; offset += group * nbytes; for (i = 0; i < nbytes; i++) if (!in_use (bitmap, i)) { if (p) printf (", "); - print_number(i + offset); + print_number((i + offset) * ratio); for (j = i; j < nbytes && !in_use (bitmap, j); j++) ; if (--j != i) { fputc('-', stdout); - print_number(j + offset); + print_number((j + offset) * ratio); i = j; } p = 1; @@ -153,7 +154,7 @@ static void list_desc (ext2_filsys fs) blk64_t blk_itr = fs->super->s_first_data_block; ext2_ino_t ino_itr = 1; - block_nbytes = EXT2_BLOCKS_PER_GROUP(fs->super) / 8; + block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; if (fs->block_map) @@ -238,18 +239,19 @@ static void list_desc (ext2_filsys fs) fputs(_(" Free blocks: "), stdout); ext2fs_get_block_bitmap_range2(fs->block_map, blk_itr, block_nbytes << 3, block_bitmap); - print_free (i, block_bitmap, - fs->super->s_blocks_per_group, - fs->super->s_first_data_block); + print_free(i, block_bitmap, + fs->super->s_clusters_per_group, + fs->super->s_first_data_block, + fs->cluster_ratio); fputc('\n', stdout); - blk_itr += fs->super->s_blocks_per_group; + blk_itr += fs->super->s_clusters_per_group; } if (inode_bitmap) { fputs(_(" Free inodes: "), stdout); ext2fs_get_inode_bitmap_range2(fs->inode_map, ino_itr, inode_nbytes << 3, inode_bitmap); - print_free (i, inode_bitmap, - fs->super->s_inodes_per_group, 1); + print_free(i, inode_bitmap, + fs->super->s_inodes_per_group, 1, 1); fputc('\n', stdout); ino_itr += fs->super->s_inodes_per_group; } diff --git a/misc/mke2fs.c b/misc/mke2fs.c index 9798b88..079638f 100644 --- a/misc/mke2fs.c +++ b/misc/mke2fs.c @@ -815,7 +815,8 @@ static __u32 ok_features[3] = { EXT4_FEATURE_RO_COMPAT_DIR_NLINK| EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE| EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| - EXT4_FEATURE_RO_COMPAT_GDT_CSUM + EXT4_FEATURE_RO_COMPAT_GDT_CSUM| + EXT4_FEATURE_RO_COMPAT_BIGALLOC }; @@ -1252,7 +1253,7 @@ profile_error: } while ((c = getopt (argc, argv, - "b:cf:g:G:i:jl:m:no:qr:s:t:vE:FI:J:KL:M:N:O:R:ST:U:V")) != EOF) { + "b:cg:i:jl:m:no:qr:s:t:vC:E:FG:I:J:KL:M:N:O:R:ST:U:V")) != EOF) { switch (c) { case 'b': blocksize = strtol(optarg, &tmp, 0); @@ -1275,17 +1276,17 @@ profile_error: case 'c': /* Check for bad blocks */ cflag++; break; - case 'f': + case 'C': size = strtoul(optarg, &tmp, 0); - if (size < EXT2_MIN_BLOCK_SIZE || - size > EXT2_MAX_BLOCK_SIZE || *tmp) { + if (size < EXT2_MIN_CLUSTER_SIZE || + size > EXT2_MAX_CLUSTER_SIZE || *tmp) { com_err(program_name, 0, _("invalid fragment size - %s"), optarg); exit(1); } - fprintf(stderr, _("Warning: fragments not supported. " - "Ignoring -f option\n")); + fs_param.s_log_cluster_size = + int_log2(size >> EXT2_MIN_CLUSTER_LOG_SIZE); break; case 'g': fs_param.s_blocks_per_group = strtoul(optarg, &tmp, 0); @@ -1515,8 +1516,6 @@ profile_error: check_plausibility(device_name); check_mount(device_name, force, _("filesystem")); - fs_param.s_log_cluster_size = fs_param.s_log_block_size; - /* Determine the size of the device (if possible) */ if (noaction && fs_blocks_count) { dev_size = fs_blocks_count; @@ -1752,16 +1751,24 @@ profile_error: } } + fs_param.s_log_block_size = + int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); + if (fs_param.s_feature_ro_compat & EXT4_FEATURE_RO_COMPAT_BIGALLOC) { + if (fs_param.s_log_cluster_size == 0) + fs_param.s_log_cluster_size = + fs_param.s_log_block_size + 4; + } else + fs_param.s_log_cluster_size = fs_param.s_log_block_size; + if (inode_ratio == 0) { inode_ratio = get_int_from_profile(fs_types, "inode_ratio", 8192); if (inode_ratio < blocksize) inode_ratio = blocksize; + if (inode_ratio < EXT2_CLUSTER_SIZE(&fs_param)) + inode_ratio = EXT2_CLUSTER_SIZE(&fs_param); } - fs_param.s_log_cluster_size = fs_param.s_log_block_size = - int_log2(blocksize >> EXT2_MIN_BLOCK_LOG_SIZE); - #ifdef HAVE_BLKID_PROBE_GET_TOPOLOGY retval = get_device_geometry(device_name, &fs_param, psector_size); if (retval < 0) { @@ -2049,6 +2056,33 @@ static int mke2fs_discard_device(ext2_filsys fs) return retval; } +static fix_cluster_bg_counts(ext2_filsys fs) +{ + blk64_t cluster, num_clusters, tot_free; + int grp_free, num_free, group, num; + + num_clusters = ext2fs_blocks_count(fs->super) / fs->cluster_ratio; + tot_free = num_free = num = group = grp_free = 0; + for (cluster = fs->super->s_first_data_block / fs->cluster_ratio; + cluster < num_clusters; cluster++) { + if (!ext2fs_test_block_bitmap2(fs->block_map, cluster)) { + grp_free++; + tot_free++; + } + num++; + if ((num == fs->super->s_clusters_per_group) || + (cluster == num_clusters-1)) { + printf("Group %d has free #: %d\n", group, grp_free); + ext2fs_bg_free_blocks_count_set(fs, group, grp_free); + ext2fs_group_desc_csum_set(fs, group); + num = 0; + grp_free = 0; + group++; + } + } + ext2fs_free_blocks_count_set(fs->super, tot_free); +} + int main (int argc, char *argv[]) { errcode_t retval = 0; @@ -2367,6 +2401,17 @@ int main (int argc, char *argv[]) } no_journal: + if (EXT2_HAS_RO_COMPAT_FEATURE(&fs_param, + EXT4_FEATURE_RO_COMPAT_BIGALLOC)) { + ext2fs_block_bitmap cluster_map; + + retval = ext2fs_convert_to_cluster_bitmap(fs, fs->block_map, + &cluster_map); + ext2fs_free_block_bitmap(fs->block_map); + fs->block_map = cluster_map; + fix_cluster_bg_counts(fs); + } + if (!quiet) printf(_("Writing superblocks and " "filesystem accounting information: "));