The code to recalculate the checksums in an extent tree (which is needed after an inode is relocated so it has a different inode number) was duplicated in tune2fs and resize2fs. In addition, this work could be done in a much more efficient way inside lib/ext2fs/extent.c. This commit creates a new library function which corrects the checksums in an inode's extent tree, named: ext2fs_fix_extents_checksums() Signed-off-by: Theodore Ts'o <tytso@xxxxxxx> --- lib/ext2fs/ext2fs.h | 4 ++- lib/ext2fs/extent.c | 48 ++++++++++++++++++++++++++++++++++++ misc/tune2fs.c | 60 +-------------------------------------------- resize/resize2fs.c | 56 ++---------------------------------------- 4 files changed, 54 insertions(+), 114 deletions(-) diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 185be5df5..a5fc90a9e 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -1295,7 +1295,9 @@ extern errcode_t ext2fs_extent_goto(ext2_extent_handle_t handle, extern errcode_t ext2fs_extent_goto2(ext2_extent_handle_t handle, int leaf_level, blk64_t blk); extern errcode_t ext2fs_extent_fix_parents(ext2_extent_handle_t handle); -size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); +extern size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle); +extern errcode_t ext2fs_fix_extents_checksums(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode); /* fallocate.c */ #define EXT2_FALLOCATE_ZERO_BLOCKS (0x1) diff --git a/lib/ext2fs/extent.c b/lib/ext2fs/extent.c index a9cdae797..ac3dbfec9 100644 --- a/lib/ext2fs/extent.c +++ b/lib/ext2fs/extent.c @@ -1737,6 +1737,54 @@ size_t ext2fs_max_extent_depth(ext2_extent_handle_t handle) return last_result; } +errcode_t ext2fs_fix_extents_checksums(ext2_filsys fs, ext2_ino_t ino, + struct ext2_inode *inode) +{ + ext2_extent_handle_t handle; + struct ext2fs_extent extent; + errcode_t errcode; + int save_flags = fs->flags; + + if (!ext2fs_has_feature_metadata_csum(fs->super) || + (inode && !(inode->i_flags & EXT4_EXTENTS_FL))) + return 0; + + errcode = ext2fs_extent_open2(fs, ino, inode, &handle); + if (errcode) { + if (errcode == EXT2_ET_INODE_NOT_EXTENT) + errcode = 0; + return errcode; + } + + fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; + errcode = ext2fs_extent_get(handle, EXT2_EXTENT_ROOT, &extent); + if (errcode) + goto out; + + do { + /* 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); + if (errcode == EXT2_ET_EXTENT_CSUM_INVALID) + errcode = update_path(handle); + } while (errcode == 0); + +out: + /* Ok if we run off the end */ + if (errcode == EXT2_ET_EXTENT_NO_NEXT) + errcode = 0; + ext2fs_extent_free(handle); + fs->flags = save_flags; + return errcode; +} + #ifdef DEBUG /* * Override debugfs's prompt diff --git a/misc/tune2fs.c b/misc/tune2fs.c index a680b461c..616bdc630 100644 --- a/misc/tune2fs.c +++ b/misc/tune2fs.c @@ -497,64 +497,6 @@ static void convert_64bit(ext2_filsys fs, int direction) fprintf(stderr, _("' to disable 64-bit mode.\n")); } -/* Rewrite extents */ -static errcode_t rewrite_extents(ext2_filsys fs, ext2_ino_t ino, - struct ext2_inode *inode) -{ - ext2_extent_handle_t handle; - struct ext2fs_extent extent; - errcode_t errcode; - struct ext2_extent_info info; - - if (!(inode->i_flags & EXT4_EXTENTS_FL) || - !ext2fs_has_feature_metadata_csum(fs->super)) - return 0; - - 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; -} - /* * Rewrite directory blocks with checksums */ @@ -849,7 +791,7 @@ static void rewrite_one_inode(struct rewrite_context *ctx, ext2_ino_t ino, if (retval) fatal_err(retval, "while writing inode"); - retval = rewrite_extents(ctx->fs, ino, inode); + retval = ext2fs_fix_extents_checksums(ctx->fs, ino, inode); if (retval) fatal_err(retval, "while rewriting extents"); diff --git a/resize/resize2fs.c b/resize/resize2fs.c index 38032e5c3..c2e10471b 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -1927,59 +1927,6 @@ out: 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 void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)), errcode_t code EXT2FS_ATTR((unused)), const char *fmt EXT2FS_ATTR((unused)), @@ -2276,7 +2223,8 @@ remap_blocks: /* Fix up extent block checksums with the new inode number */ if (ext2fs_has_feature_metadata_csum(rfs->old_fs->super) && (inode->i_flags & EXT4_EXTENTS_FL)) { - retval = rewrite_extents(rfs->old_fs, new_inode); + retval = ext2fs_fix_extents_checksums(rfs->old_fs, + new_inode, NULL); if (retval) goto errout; } -- 2.18.0.rc0