2009-02-13 09:49:34

by Gui Xiaohua

[permalink] [raw]
Subject: [PATCH]:resize2fs:adjust the inode before inode_tables were covered

Hi Ted
There is a problem in your patch for resize2fs -M.
You unmark the inode_table block in new fs,the blocks
which needed to be moved will cover the the inode_table
blocks with its content.In inode_scan_and_fix func, we will
scan the inode which in the old fs, but the inode table block
had been coverd,then error occurs.
I had fixed the problem through adjust the inode before blocks
be moved.

Signed-off-by: Gui Xiaohua <[email protected]>
--- e2fsprogs_org/resize/resize2fs.c 2009-02-05 09:33:26.000000000 +0800
+++ e2fsprogs/resize/resize2fs.c 2009-02-05 19:17:34.000000000 +0800
@@ -49,6 +49,7 @@ static errcode_t inode_ref_fix(ext2_resi
static errcode_t move_itables(ext2_resize_t rfs);
static errcode_t fix_resize_inode(ext2_filsys fs);
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
+static errcode_t inode_swap(ext2_resize_t rfs);

/*
* Some helper CPP macros
@@ -235,18 +236,23 @@ static void fix_uninit_block_bitmaps(ext
* If the group descriptor's bitmap and inode table blocks are valid,
* release them in the specified filesystem data structure
*/
-static void free_gdp_blocks(ext2_filsys fs, struct ext2_group_desc *gdp)
+static void free_gdp_blocks(ext2_filsys old_fs, ext2_filsys fs,
+ struct ext2_group_desc *gdp)
{
blk_t blk;
int j;

if (gdp->bg_block_bitmap &&
- (gdp->bg_block_bitmap < fs->super->s_blocks_count))
+ (gdp->bg_block_bitmap < fs->super->s_blocks_count)) {
ext2fs_block_alloc_stats(fs, gdp->bg_block_bitmap, -1);
+ ext2fs_block_alloc_stats(old_fs, gdp->bg_block_bitmap, -1);
+ }

if (gdp->bg_inode_bitmap &&
- (gdp->bg_inode_bitmap < fs->super->s_blocks_count))
+ (gdp->bg_inode_bitmap < fs->super->s_blocks_count)) {
ext2fs_block_alloc_stats(fs, gdp->bg_inode_bitmap, -1);
+ ext2fs_block_alloc_stats(old_fs, gdp->bg_inode_bitmap, -1);
+ }

if (gdp->bg_inode_table == 0 ||
(gdp->bg_inode_table >= fs->super->s_blocks_count))
@@ -257,6 +263,7 @@ static void free_gdp_blocks(ext2_filsys
if (blk >= fs->super->s_blocks_count)
break;
ext2fs_block_alloc_stats(fs, blk, -1);
+ ext2fs_block_alloc_stats(old_fs, blk, -1);
}
}

@@ -403,14 +410,6 @@ retry:
* can exit now.
*/
if (old_fs->group_desc_count > fs->group_desc_count) {
- /*
- * Check the block groups that we are chopping off
- * and free any blocks associated with their metadata
- */
- for (i = fs->group_desc_count;
- i < old_fs->group_desc_count; i++) {
- free_gdp_blocks(fs, &old_fs->group_desc[i]);
- }
retval = 0;
goto errout;
}
@@ -554,6 +553,21 @@ static errcode_t adjust_superblock(ext2_
if (retval)
goto errout;

+ if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
+ /*
+ * Check the block groups that we are chopping off
+ * and free any blocks associated with their metadata
+ */
+ retval = inode_swap(rfs);
+ if (retval)
+ goto errout;
+ for (i = fs->group_desc_count;
+ i < rfs->old_fs->group_desc_count; i++) {
+ free_gdp_blocks(rfs->old_fs, fs,
+ &rfs->old_fs->group_desc[i]);
+ }
+ }
+
/*
* Check to make sure there are enough inodes
*/
@@ -1964,3 +1978,92 @@ blk_t calculate_minimum_resize_size(ext2

return blks_needed;
}
+
+/*
+ * adjust the inodes info
+ */
+static errcode_t inode_swap(ext2_resize_t rfs)
+{
+ int inode_size, i;
+ char *block_buf = 0;
+ errcode_t retval;
+ ext2_ino_t ino, new_inode, start_to_move;
+ ext2_inode_scan scan = NULL;
+ struct ext2_inode *inode = NULL;
+
+ retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
+ ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
+ inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
+ inode = malloc(inode_size);
+ if (!inode) {
+ retval = ENOMEM;
+ goto errout;
+ }
+
+ start_to_move = (rfs->new_fs->group_desc_count *
+ rfs->new_fs->super->s_inodes_per_group);
+ /*
+ * First, copy all of the inodes that need to be moved
+ * elsewhere in the inode table
+ */
+ while (1) {
+ retval = ext2fs_get_next_inode_full(scan, &ino,
+ inode, inode_size);
+ if (retval)
+ goto errout;
+
+ if (!ino)
+ break;
+ if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
+ continue; /* inode not in use */
+ if (ino <= start_to_move)
+ continue; /* Don't need to move it. */
+
+ /*
+ * Find a new inode
+ */
+ retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0,
+ &new_inode);
+ if (retval)
+ goto errout;
+
+ ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
+ LINUX_S_ISDIR(inode->i_mode));
+ ext2fs_inode_alloc_stats2(rfs->old_fs, new_inode, +1,
+ LINUX_S_ISDIR(inode->i_mode));
+ ext2fs_inode_alloc_stats2(rfs->old_fs, ino, -1,
+ LINUX_S_ISDIR(inode->i_mode));
+
+ inode->i_ctime = time(0);
+ retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
+ inode, inode_size);
+ if (retval)
+ goto errout;
+
+ if (!rfs->imap) {
+ retval = ext2fs_create_extent_table(&rfs->imap, 0);
+ if (retval)
+ goto errout;
+ }
+ ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
+ }
+
+ /*
+ *reduce the count of circle and prevent read wrong blocks
+ *while inode_scan_and_fix
+ */
+ for (i = rfs->new_fs->group_desc_count;
+ i < rfs->old_fs->group_desc_count; i++) {
+ rfs->old_fs->group_desc[i].bg_itable_unused =
+ EXT2_INODES_PER_GROUP(rfs->old_fs->super);
+ }
+
+errout:
+ if (scan)
+ ext2fs_close_inode_scan(scan);
+ if (block_buf)
+ ext2fs_free_mem(&block_buf);
+ if (inode)
+ free(inode);
+ return retval;
+}