Skip to content

Commit

Permalink
resize2fs: quickly rewrite extent blocks when moving an inode w/ meta…
Browse files Browse the repository at this point in the history
…data_csum

When we're moving an inode on a metadata_csum filesystem, we need to
rewrite the checksum of all interior nodes of the extent tree.  The
current code does this inefficiently via set_bmap, but we can do this
more efficiently through direct iteration of the extent tree.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
  • Loading branch information
djwong authored and tytso committed Dec 14, 2014
1 parent 4495c5a commit fb30384
Showing 1 changed file with 64 additions and 10 deletions.
74 changes: 64 additions & 10 deletions resize/resize2fs.c
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1492,16 +1492,6 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
} }
} }


/*
* If we moved inodes and metadata_csum is enabled, we must force the
* extent block to be rewritten with new checksum.
*/
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
pb->has_extents &&
pb->old_ino != pb->ino)
ret |= BLOCK_CHANGED;

if (pb->is_dir) { if (pb->is_dir) {
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino, retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
block, (int) blockcnt); block, (int) blockcnt);
Expand Down Expand Up @@ -1581,6 +1571,59 @@ static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino,
return err; return err;
} }


/* Rewrite extents */
static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino)
{
ext2_extent_handle_t handle;
struct ext2fs_extent extent;
errcode_t errcode;
struct ext2_extent_info info;

errcode = ext2fs_extent_open(fs, ino, &handle);
if (errcode)
return errcode;

errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent);
if (errcode)
goto out;

do {
errcode = ext2fs_extent_get_info(handle, &info);
if (errcode)
break;

/*
* If this is the first extent in an extent block that we
* haven't visited, rewrite the extent to force the ETB
* checksum to be rewritten.
*/
if (info.curr_entry == 1 && info.curr_level != 0 &&
!(extent.e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)) {
errcode = ext2fs_extent_replace(handle, 0, &extent);
if (errcode)
break;
}

/* Skip to the end of a block of leaf nodes */
if (extent.e_flags & EXT2_EXTENT_FLAGS_LEAF) {
errcode = ext2fs_extent_get(handle,
EXT2_EXTENT_LAST_SIB,
&extent);
if (errcode)
break;
}

errcode = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT, &extent);
} while (errcode == 0);

out:
/* Ok if we run off the end */
if (errcode == EXT2_ET_EXTENT_NO_NEXT)
errcode = 0;
ext2fs_extent_free(handle);
return errcode;
}

static errcode_t inode_scan_and_fix(ext2_resize_t rfs) static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
{ {
struct process_block_struct pb; struct process_block_struct pb;
Expand Down Expand Up @@ -1699,6 +1742,17 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
if (retval) if (retval)
goto errout; goto errout;


/* Rewrite extent block checksums with new inode number */
if (EXT2_HAS_RO_COMPAT_FEATURE(rfs->old_fs->super,
EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) &&
(inode->i_flags & EXT4_EXTENTS_FL)) {
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = rewrite_extents(rfs->old_fs, new_inode);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
}

/* /*
* Update inodes to point to new blocks; schedule directory * Update inodes to point to new blocks; schedule directory
* blocks for inode remapping. Need to write out dir blocks * blocks for inode remapping. Need to write out dir blocks
Expand Down

0 comments on commit fb30384

Please sign in to comment.