Whamcloud - gitweb
mke2fs: fix up topo complaints on regular files
[tools/e2fsprogs.git] / misc / tune2fs.c
index d2d1539..41a0638 100644 (file)
@@ -969,9 +969,15 @@ static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
                            ext2fs_block_bitmap bmap)
 {
        dgrp_t i;
+       int retval;
+       ext2_badblocks_list bb_list = 0;
        blk_t j, needed_blocks = 0;
        blk_t start_blk, end_blk;
 
+       retval = ext2fs_read_bb_inode(fs, &bb_list);
+       if (retval)
+               return retval;
+
        for (i = 0; i < fs->group_desc_count; i++) {
                start_blk = fs->group_desc[i].bg_inode_table +
                                        fs->inode_blocks_per_group;
@@ -981,10 +987,14 @@ static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
 
                for (j = start_blk; j < end_blk; j++) {
                        if (ext2fs_test_block_bitmap(fs->block_map, j)) {
-                               /* FIXME!!
-                                * What happens if the block is marked
-                                * as a bad block
+                               /*
+                                * IF the block is a bad block we fail
                                 */
+                               if (ext2fs_badblocks_list_test(bb_list, j)) {
+                                       ext2fs_badblocks_list_free(bb_list);
+                                       return ENOSPC;
+                               }
+
                                ext2fs_mark_block_bitmap(bmap, j);
                        } else {
                                /*
@@ -997,16 +1007,46 @@ static int get_move_bitmaps(ext2_filsys fs, int new_ino_blks_per_grp,
                needed_blocks += end_blk - start_blk;
        }
 
+       ext2fs_badblocks_list_free(bb_list);
        if (needed_blocks > fs->super->s_free_blocks_count)
                return ENOSPC;
 
        return 0;
 }
 
+static int ext2fs_is_meta_block(ext2_filsys fs, blk_t blk)
+{
+       dgrp_t group;
+       group = ext2fs_group_of_blk(fs, blk);
+       if (fs->group_desc[group].bg_block_bitmap == blk)
+               return 1;
+       if (fs->group_desc[group].bg_inode_bitmap == blk)
+               return 1;
+       return 0;
+}
+
+static int ext2fs_is_block_in_group(ext2_filsys fs, dgrp_t group, blk_t blk)
+{
+       blk_t start_blk, end_blk;
+       start_blk = fs->super->s_first_data_block +
+                       EXT2_BLOCKS_PER_GROUP(fs->super) * group;
+       /*
+        * We cannot get new block beyond end_blk for for the last block group
+        * so we can check with EXT2_BLOCKS_PER_GROUP even for last block group
+        */
+       end_blk   = start_blk + EXT2_BLOCKS_PER_GROUP(fs->super);
+       if (blk >= start_blk && blk <= end_blk)
+               return 1;
+       return 0;
+}
+
 static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
 {
+
        char *buf;
+       dgrp_t group;
        errcode_t retval;
+       int meta_data = 0;
        blk_t blk, new_blk, goal;
        struct blk_move *bmv;
 
@@ -1019,11 +1059,31 @@ static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
                if (!ext2fs_test_block_bitmap(bmap, blk))
                        continue;
 
-               goal = new_blk;
+               if (ext2fs_is_meta_block(fs, blk)) {
+                       /*
+                        * If the block is mapping a fs meta data block
+                        * like group desc/block bitmap/inode bitmap. We
+                        * should find a block in the same group and fix
+                        * the respective fs metadata pointers. Otherwise
+                        * fail
+                        */
+                       group = ext2fs_group_of_blk(fs, blk);
+                       goal = ext2fs_group_first_block(fs, group);
+                       meta_data = 1;
+
+               } else {
+                       goal = new_blk;
+               }
                retval = ext2fs_new_block(fs, goal, NULL, &new_blk);
                if (retval)
                        goto err_out;
 
+               /* new fs meta data block should be in the same group */
+               if (meta_data && !ext2fs_is_block_in_group(fs, group, new_blk)) {
+                       retval = ENOSPC;
+                       goto err_out;
+               }
+
                /* Mark this block as allocated */
                ext2fs_mark_block_bitmap(fs->block_map, new_blk);
 
@@ -1158,6 +1218,36 @@ err_out:
        return retval;
 }
 
+/*
+ * We need to scan for inode and block bitmaps that may need to be
+ * moved.  This can take place if the filesystem was formatted for
+ * RAID arrays using the mke2fs's extended option "stride".
+ */
+static int group_desc_scan_and_fix(ext2_filsys fs, ext2fs_block_bitmap bmap)
+{
+       dgrp_t i;
+       blk_t blk, new_blk;
+
+       for (i = 0; i < fs->group_desc_count; i++) {
+               blk = fs->group_desc[i].bg_block_bitmap;
+               if (ext2fs_test_block_bitmap(bmap, blk)) {
+                       new_blk = translate_block(blk);
+                       if (!new_blk)
+                               continue;
+                       fs->group_desc[i].bg_block_bitmap = new_blk;
+               }
+
+               blk = fs->group_desc[i].bg_inode_bitmap;
+               if (ext2fs_test_block_bitmap(bmap, blk)) {
+                       new_blk = translate_block(blk);
+                       if (!new_blk)
+                               continue;
+                       fs->group_desc[i].bg_inode_bitmap = new_blk;
+               }
+       }
+       return 0;
+}
+
 static int expand_inode_table(ext2_filsys fs, unsigned long new_ino_size)
 {
        dgrp_t i;
@@ -1350,6 +1440,10 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
        if (retval)
                goto err_out_undo;
 
+       retval = group_desc_scan_and_fix(fs, bmap);
+       if (retval)
+               goto err_out_undo;
+
        retval = expand_inode_table(fs, new_size);
        if (retval)
                goto err_out_undo;