Whamcloud - gitweb
mke2fs: fix up topo complaints on regular files
[tools/e2fsprogs.git] / misc / tune2fs.c
index 044468b..41a0638 100644 (file)
@@ -95,7 +95,9 @@ struct blk_move {
 
 static const char *please_fsck = N_("Please run e2fsck on the filesystem.\n");
 
+#ifdef CONFIG_BUILD_FINDFS
 void do_findfs(int argc, char **argv);
+#endif
 
 static void usage(void)
 {
@@ -529,8 +531,7 @@ static void add_journal(ext2_filsys fs)
        return;
 
 err:
-       if (journal_device)
-               free(journal_device);
+       free(journal_device);
        exit(1);
 }
 
@@ -720,7 +721,8 @@ static void parse_tune2fs_options(int argc, char **argv)
                        break;
                case 'm':
                        reserved_ratio = strtod(optarg, &tmp);
-                       if (*tmp || reserved_ratio > 50) {
+                       if (*tmp || reserved_ratio > 50 ||
+                           reserved_ratio < 0) {
                                com_err(program_name, 0,
                                        _("bad reserved block ratio - %s"),
                                        optarg);
@@ -836,6 +838,7 @@ static void parse_tune2fs_options(int argc, char **argv)
        }
 }
 
+#ifdef CONFIG_BUILD_FINDFS
 void do_findfs(int argc, char **argv)
 {
        char    *dev;
@@ -854,6 +857,7 @@ void do_findfs(int argc, char **argv)
        puts(dev);
        exit(0);
 }
+#endif
 
 static void parse_extended_opts(ext2_filsys fs, const char *opts)
 {
@@ -957,13 +961,23 @@ static void parse_extended_opts(ext2_filsys fs, const char *opts)
        free(buf);
 }
 
-static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp,
-                          ext2fs_block_bitmap bmap)
+/*
+ * Fill in the block bitmap bmap with the information regarding the
+ * blocks to be moved
+ */
+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;
@@ -973,12 +987,15 @@ static int get_move_bitmap(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);
-                               needed_blocks++;
                        } else {
                                /*
                                 * We are going to use this block for
@@ -987,19 +1004,50 @@ static int get_move_bitmap(ext2_filsys fs, int new_ino_blks_per_grp,
                                ext2fs_mark_block_bitmap(fs->block_map, j);
                        }
                }
+               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;
-       blk_t blk, new_blk;
+       int meta_data = 0;
+       blk_t blk, new_blk, goal;
        struct blk_move *bmv;
 
        retval = ext2fs_get_mem(fs->blocksize, &buf);
@@ -1011,10 +1059,31 @@ static int move_block(ext2_filsys fs, ext2fs_block_bitmap bmap)
                if (!ext2fs_test_block_bitmap(bmap, blk))
                        continue;
 
-               retval = ext2fs_new_block(fs, new_blk, NULL, &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);
 
@@ -1147,7 +1216,36 @@ err_out:
        ext2fs_free_mem(&block_buf);
 
        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)
@@ -1295,8 +1393,7 @@ static void free_blk_move_list(void)
                list_del(entry);
                ext2fs_free_mem(&bmv);
        }
-
-       return ;
+       return;
 }
 
 static int resize_inode(ext2_filsys fs, unsigned long new_size)
@@ -1323,24 +1420,33 @@ static int resize_inode(ext2_filsys fs, unsigned long new_size)
 
        retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
                                                &bmap);
-       if (retval)
+       if (retval) {
+               fputs(_("Failed to allocate block bitmap when "
+                               "increasing inode size\n"), stderr);
                return retval;
-
-       retval = get_move_bitmap(fs, new_ino_blks_per_grp, bmap);
-       if (retval)
+       }
+       retval = get_move_bitmaps(fs, new_ino_blks_per_grp, bmap);
+       if (retval) {
+               fputs(_("Not enough space to increase inode size \n"), stderr);
                goto err_out;
-
+       }
        retval = move_block(fs, bmap);
-       if (retval)
+       if (retval) {
+               fputs(_("Failed to relocate blocks during inode resize \n"),
+                     stderr);
                goto err_out;
-
+       }
        retval = inode_scan_and_fix(fs, bmap);
        if (retval)
-               goto err_out;
+               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;
+               goto err_out_undo;
 
        ext2fs_calculate_summary_stats(fs);
 
@@ -1354,13 +1460,22 @@ err_out:
        ext2fs_free_block_bitmap(bmap);
 
        return retval;
+
+err_out_undo:
+       free_blk_move_list();
+       ext2fs_free_block_bitmap(bmap);
+       fputs(_("Error in resizing the inode size.\n"
+                       "Run e2undo to undo the "
+                       "file system changes. \n"), stderr);
+
+       return retval;
 }
 
 static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
 {
        errcode_t retval = 0;
        const char *tdb_dir;
-       char tdb_file[PATH_MAX];
+       char *tdb_file;
        char *dev_name, *tmp_name;
 
 #if 0 /* FIXME!! */
@@ -1373,6 +1488,12 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
                                        &tdb_dir);
 #endif
        tmp_name = strdup(name);
+       if (!tmp_name) {
+       alloc_fn_fail:
+               com_err(program_name, ENOMEM, 
+                       _("Couldn't allocate memory for tdb filename\n"));
+               return ENOMEM;
+       }
        dev_name = basename(tmp_name);
 
        tdb_dir = getenv("E2FSPROGS_UNDO_DIR");
@@ -1383,6 +1504,9 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
            access(tdb_dir, W_OK))
                return 0;
 
+       tdb_file = malloc(strlen(tdb_dir) + 9 + strlen(dev_name) + 7 + 1);
+       if (!tdb_file)
+               goto alloc_fn_fail;
        sprintf(tdb_file, "%s/tune2fs-%s.e2undo", tdb_dir, dev_name);
 
        if (!access(tdb_file, F_OK)) {
@@ -1391,6 +1515,7 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
                        com_err(program_name, retval,
                                _("while trying to delete %s"),
                                tdb_file);
+                       free(tdb_file);
                        return retval;
                }
        }
@@ -1401,6 +1526,7 @@ static int tune2fs_setup_tdb(const char *name, io_manager *io_ptr)
        printf(_("To undo the tune2fs operation please run "
                 "the command\n    e2undo %s %s\n\n"),
                 tdb_file, name);
+       free(tdb_file);
        free(tmp_name);
        return retval;
 }
@@ -1422,8 +1548,10 @@ int main(int argc, char **argv)
                program_name = *argv;
        add_error_table(&et_ext2_error_table);
 
+#ifdef CONFIG_BUILD_FINDFS
        if (strcmp(get_progname(argv[0]), "findfs") == 0)
                do_findfs(argc, argv);
+#endif
        if (strcmp(get_progname(argv[0]), "e2label") == 0)
                parse_e2label_options(argc, argv);
        else
@@ -1456,7 +1584,7 @@ retry_open:
                 * file.
                 */
                if (new_inode_size == EXT2_INODE_SIZE(fs->super)) {
-                       fprintf(stderr, _("The inode size is already %d\n"),
+                       fprintf(stderr, _("The inode size is already %lu\n"),
                                new_inode_size);
                        exit(1);
                }
@@ -1657,11 +1785,7 @@ retry_open:
                 * with the new free inode count
                 */
                fs->flags &= ~EXT2_FLAG_SUPER_ONLY;
-               if (resize_inode(fs, new_inode_size)) {
-                       fputs(_("Error in resizing the inode size.\n"
-                               "Run e2undo to undo the "
-                               "file system changes. \n"), stderr);
-               } else {
+               if (resize_inode(fs, new_inode_size) == 0) {
                        printf(_("Setting inode size %lu\n"),
                                                        new_inode_size);
                }
@@ -1679,6 +1803,7 @@ retry_open:
                ext2fs_mark_super_dirty(fs);
                printf(_("Setting stripe width to %d\n"), stripe_width);
        }
+       free(device_name);
        remove_error_table(&et_ext2_error_table);
        return (ext2fs_close(fs) ? 1 : 0);
 }