X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=misc%2Ftune2fs.c;h=41a063826659f0ba0a024f1bc9da45c252d0e4c2;hb=13b0b1231ed28aac75ba336de7a8cb3b4611ce68;hp=044468b1d89ebb25a4eff6d1723c8615f48b509b;hpb=ec43da2f35c54589e8aa0663d9cf44f86895242a;p=tools%2Fe2fsprogs.git diff --git a/misc/tune2fs.c b/misc/tune2fs.c index 044468b..41a0638 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -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); }