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)
{
return;
err:
- if (journal_device)
- free(journal_device);
+ free(journal_device);
exit(1);
}
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);
}
}
+#ifdef CONFIG_BUILD_FINDFS
void do_findfs(int argc, char **argv)
{
char *dev;
puts(dev);
exit(0);
}
+#endif
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;
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
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);
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);
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)
list_del(entry);
ext2fs_free_mem(&bmv);
}
-
- return ;
+ return;
}
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);
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!! */
&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");
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)) {
com_err(program_name, retval,
_("while trying to delete %s"),
tdb_file);
+ free(tdb_file);
return retval;
}
}
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;
}
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
* 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);
}
* 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);
}
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);
}