From 25567a7b0fa98b390fd1ff0d4702b29c23a75bbb Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 5 Jul 2011 13:42:07 -0400 Subject: [PATCH] e2fsck, libext2fs: support for bigalloc file systems with a blocksize of 1024 Filesystems with a blocksize of 1024 have the superblock starting at block #1. However, the first data block in the superblock is 0 to simplify the cluster calculations. So we must compensate for this in a number of places, mostly in the ext2fs library, but also in e2fsck. Signed-off-by: "Theodore Ts'o" --- e2fsck/super.c | 5 ++- lib/ext2fs/alloc_sb.c | 3 ++ lib/ext2fs/alloc_tables.c | 72 ++++++++++++++++++++------------------- lib/ext2fs/closefs.c | 2 ++ lib/ext2fs/openfs.c | 2 ++ lib/ext2fs/res_gdt.c | 15 ++++++-- 6 files changed, 60 insertions(+), 39 deletions(-) diff --git a/e2fsck/super.c b/e2fsck/super.c index 40cfc4fb..2fffc534 100644 --- a/e2fsck/super.c +++ b/e2fsck/super.c @@ -400,6 +400,8 @@ void check_resize_inode(e2fsck_t ctx) gdt_off = fs->desc_blocks; pblk = fs->super->s_first_data_block + 1 + fs->desc_blocks; + if (fs->blocksize == 1024 && fs->super->s_first_data_block == 0) + pblk++; /* Deal with 1024 blocksize bigalloc fs */ for (i = 0; i < fs->super->s_reserved_gdt_blocks / 4; i++, gdt_off++, pblk++) { gdt_off %= fs->blocksize/4; @@ -555,7 +557,8 @@ void check_super_block(e2fsck_t ctx) } } - should_be = (sb->s_log_block_size == 0) ? 1 : 0; + should_be = (sb->s_log_block_size == 0 && + EXT2FS_CLUSTER_RATIO(fs) == 1) ? 1 : 0; if (sb->s_first_data_block != should_be) { pctx.blk = sb->s_first_data_block; pctx.blk2 = should_be; diff --git a/lib/ext2fs/alloc_sb.c b/lib/ext2fs/alloc_sb.c index d5fca3b2..09786a75 100644 --- a/lib/ext2fs/alloc_sb.c +++ b/lib/ext2fs/alloc_sb.c @@ -59,6 +59,9 @@ int ext2fs_reserve_super_and_bgd(ext2_filsys fs, if (super_blk || (group == 0)) ext2fs_mark_block_bitmap2(bmap, super_blk); + if ((group == 0) && (fs->blocksize == 1024) && + EXT2FS_CLUSTER_RATIO(fs) > 1) + ext2fs_mark_block_bitmap2(bmap, 0); if (old_desc_blk) { if (fs->super->s_reserved_gdt_blocks && fs->block_map == bmap) diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c index 1c4532b6..ee2ac4d2 100644 --- a/lib/ext2fs/alloc_tables.c +++ b/lib/ext2fs/alloc_tables.c @@ -35,45 +35,43 @@ * tables can be allocated continously and in order. */ static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk, - ext2fs_block_bitmap bmap, int offset, int size, + ext2fs_block_bitmap bmap, int rem_grp, int elem_size) { - int flexbg, flexbg_size; + int flexbg, flexbg_size, size; blk64_t last_blk, first_free = 0; dgrp_t last_grp; - flexbg_size = 1 << fs->super->s_log_groups_per_flex; - flexbg = group / flexbg_size; + size = rem_grp * elem_size; if (size > (int) (fs->super->s_blocks_per_group / 8)) size = (int) fs->super->s_blocks_per_group / 8; - if (offset) - offset -= 1; - /* * Don't do a long search if the previous block * search is still valid. */ - if (start_blk && group % flexbg_size) { - if (ext2fs_test_block_bitmap_range2(bmap, start_blk + elem_size, - size)) - return start_blk + elem_size; - } + if (start_blk && ext2fs_test_block_bitmap_range2(bmap, start_blk, + elem_size)) + return start_blk; start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg); last_grp = group | (flexbg_size - 1); - if (last_grp > fs->group_desc_count) - last_grp = fs->group_desc_count; + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; last_blk = ext2fs_group_last_block2(fs, last_grp); /* Find the first available block */ - if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, 1, bmap, - &first_free)) + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size, + bmap, &first_free) == 0) return first_free; - if (ext2fs_get_free_blocks2(fs, first_free + offset, last_blk, size, - bmap, &first_free)) + if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size, + bmap, &first_free) == 0) + return first_free; + + if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap, + &first_free) == 0) return first_free; return first_free; @@ -98,9 +96,9 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, fs->super->s_log_groups_per_flex) { flexbg_size = 1 << fs->super->s_log_groups_per_flex; last_grp = group | (flexbg_size - 1); - rem_grps = last_grp - group; - if (last_grp > fs->group_desc_count) - last_grp = fs->group_desc_count; + if (last_grp > fs->group_desc_count-1) + last_grp = fs->group_desc_count-1; + rem_grps = last_grp - group + 1; } /* @@ -122,10 +120,10 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, if (flexbg_size) { blk64_t prev_block = 0; - if (group && ext2fs_block_bitmap_loc(fs, group - 1)) - prev_block = ext2fs_block_bitmap_loc(fs, group - 1); + if (group % flexbg_size) + prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1; start_blk = flexbg_offset(fs, group, prev_block, bmap, - 0, rem_grps, 1); + rem_grps, 1); last_blk = ext2fs_group_last_block2(fs, last_grp); } @@ -150,10 +148,13 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, if (flexbg_size) { blk64_t prev_block = 0; - if (group && ext2fs_inode_bitmap_loc(fs, group - 1)) - prev_block = ext2fs_inode_bitmap_loc(fs, group - 1); + if (group % flexbg_size) + prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1; + else + prev_block = ext2fs_block_bitmap_loc(fs, group) + + flexbg_size; start_blk = flexbg_offset(fs, group, prev_block, bmap, - flexbg_size, rem_grps, 1); + rem_grps, 1); last_blk = ext2fs_group_last_block2(fs, last_grp); } @@ -181,15 +182,16 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, */ if (flexbg_size) { blk64_t prev_block = 0; - if (group && ext2fs_inode_table_loc(fs, group - 1)) - prev_block = ext2fs_inode_table_loc(fs, group - 1); - if (last_grp == fs->group_desc_count) - rem_grps = last_grp - group; + + if (group % flexbg_size) + prev_block = ext2fs_inode_table_loc(fs, group - 1) + + fs->inode_blocks_per_group; + else + prev_block = ext2fs_inode_bitmap_loc(fs, group) + + flexbg_size; + group_blk = flexbg_offset(fs, group, prev_block, bmap, - flexbg_size * 2, - fs->inode_blocks_per_group * - rem_grps, - fs->inode_blocks_per_group); + rem_grps, fs->inode_blocks_per_group); last_blk = ext2fs_group_last_block2(fs, last_grp); } diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c index 7a23e465..952f4966 100644 --- a/lib/ext2fs/closefs.c +++ b/lib/ext2fs/closefs.c @@ -73,6 +73,8 @@ errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs, int has_super; group_block = ext2fs_group_first_block2(fs, group); + if (group_block == 0 && fs->blocksize == 1024) + group_block = 1; /* Deal with 1024 blocksize && bigalloc */ if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) old_desc_blocks = fs->super->s_first_meta_bg; diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c index 283daeec..0fe42205 100644 --- a/lib/ext2fs/openfs.c +++ b/lib/ext2fs/openfs.c @@ -322,6 +322,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, goto cleanup; if (!group_block) group_block = fs->super->s_first_data_block; + if (group_block == 0 && fs->blocksize == 1024) + group_block = 1; /* Deal with 1024 blocksize && bigalloc */ dest = (char *) fs->group_desc; groups_per_block = EXT2_DESC_PER_BLOCK(fs->super); if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c index f3b39692..acce650d 100644 --- a/lib/ext2fs/res_gdt.c +++ b/lib/ext2fs/res_gdt.c @@ -67,7 +67,7 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) unsigned long long apb, inode_size; /* FIXME-64 - can't deal with extents */ blk_t dindir_blk, rsv_off, gdt_off, gdt_blk; - int dindir_dirty = 0, inode_dirty = 0; + int dindir_dirty = 0, inode_dirty = 0, sb_blk = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); @@ -82,6 +82,15 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) if (retval) goto out_free; + /* + * File systems with a blocksize of 1024 and bigalloc have + * sb->s_first_data_block of 0; yet the superblock is still at + * block #1. We compensate for it here. + */ + sb_blk = sb->s_first_data_block; + if (fs->blocksize == 1024 && sb_blk == 0) + sb_blk = 1; + /* Maximum possible file size (we donly use the dindirect blocks) */ apb = EXT2_ADDR_PER_BLOCK(sb); if ((dindir_blk = inode.i_block[EXT2_DIND_BLOCK])) { @@ -92,7 +101,7 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) if (retval) goto out_inode; } else { - blk_t goal = sb->s_first_data_block + fs->desc_blocks + + blk_t goal = sb_blk + fs->desc_blocks + sb->s_reserved_gdt_blocks + 2 + fs->inode_blocks_per_group; @@ -120,7 +129,7 @@ errcode_t ext2fs_create_resize_inode(ext2_filsys fs) } for (rsv_off = 0, gdt_off = fs->desc_blocks, - gdt_blk = sb->s_first_data_block + 1 + fs->desc_blocks; + gdt_blk = sb_blk + 1 + fs->desc_blocks; rsv_off < sb->s_reserved_gdt_blocks; rsv_off++, gdt_off++, gdt_blk++) { unsigned int three = 1, five = 5, seven = 7;