From bf188ee362233444e0951c7c457ea5f771d6246d Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Thu, 15 Sep 2016 21:42:06 +0000 Subject: [PATCH] fix inode checksums... but it also requires to fix directory checksums... so in fact it is better to just merge it in resize2fs... --- bmove.c | 7 +++ realloc-inodes.c | 118 ++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 118 insertions(+), 7 deletions(-) diff --git a/bmove.c b/bmove.c index daf52ba..7d0d8bd 100644 --- a/bmove.c +++ b/bmove.c @@ -161,6 +161,13 @@ errcode_t ext2fs_move_blocks(ext2_filsys fs, pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) && flags & EXT2_BMOVE_GET_DBLIST); + if ((inode.i_flags & EXT4_INLINE_DATA_FL) && pb.add_dir) { + /* inline data dir; update it too */ + retval = ext2fs_add_dir_block2(fs->dblist, ino, 0, 0); + if (retval) + return retval; + } + retval = ext2fs_block_iterate3(fs, ino, 0, block_buf, process_block, &pb); if (retval) return retval; diff --git a/realloc-inodes.c b/realloc-inodes.c index e89f095..54070f6 100644 --- a/realloc-inodes.c +++ b/realloc-inodes.c @@ -119,6 +119,7 @@ EXT2_FEATURE_RO_COMPAT_LARGE_FILE|\ EXT4_FEATURE_RO_COMPAT_DIR_NLINK|\ EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE|\ + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM|\ EXT4_FEATURE_RO_COMPAT_GDT_CSUM|\ EXT4_FEATURE_RO_COMPAT_BIGALLOC|\ EXT4_FEATURE_RO_COMPAT_QUOTA) @@ -202,6 +203,59 @@ ext2_ino_t realloc_search_inode_map(realloc_data *rd, ext2_ino_t old) return 0; } +/* 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; +} + /** * Move inodes from the end of each block group inode table * so the tables can be shrinked @@ -262,6 +316,15 @@ errcode_t shrink_move_inodes(realloc_data *rd) } ext2fs_inode_alloc_stats2(rd->fs, new_ino, 1, inode->i_mode & S_IFDIR); ext2fs_inode_alloc_stats2(rd->fs, ino, -1, inode->i_mode & S_IFDIR); + /* Rewrite extent block checksums with new inode number */ + if (ext2fs_has_feature_metadata_csum(rd->fs->super) && + (inode->i_flags & EXT4_EXTENTS_FL)) { + rd->fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS; + retval = rewrite_extents(rd->fs, new_ino); + rd->fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS; + if (retval) + goto out; + } // Remember mapping realloc_add_inode_map(rd, ino, new_ino); } @@ -330,6 +393,15 @@ static int change_inode_numbers_callback(ext2_ino_t dir, int entry, return 0; } +static int fix_dirent_csum_callback(ext2_ino_t dir, int entry, + struct ext2_dir_entry *dirent, int offset, + int blocksize, char *buf, void *priv_data) +{ + realloc_data *rd = priv_data; + ext2fs_dir_block_csum_set(rd->fs, dir, dirent); + return DIRENT_CHANGED; +} + /** * Change inode numbers in all directory entries */ @@ -347,6 +419,20 @@ errcode_t change_inode_numbers(realloc_data *rd) return 0; } +errcode_t fix_dirent_csums(realloc_data *rd) +{ + ext2_ino_t ino; + realloc_sort_inode_map(rd); + for (ino = 1; ino <= rd->fs->super->s_inodes_count; ino++) + { + if (ext2fs_test_inode_bitmap2(rd->fs->inode_map, ino)) + { + ext2fs_dir_iterate2(rd->fs, ino, 0, 0, fix_dirent_csum_callback, rd); + } + } + return 0; +} + /** * 1) Move inode tables * 2) Mark/unmark new/old inode table blocks @@ -357,10 +443,11 @@ errcode_t change_super_and_bgd(realloc_data *rd) blk64_t blk, end; dgrp_t grp, n_grp, flex_grp; __u32 used_ig, used_ibg, i, unus; + ext2_ino_t inum; errcode_t retval = 0; - int has_gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM); + int has_gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM|EXT4_FEATURE_RO_COMPAT_METADATA_CSUM); int cl = EXT2FS_CLUSTER_RATIO(rd->fs); - void *buf = NULL; + void *buf = NULL, *inode_buf = NULL; ext2fs_flush(rd->fs); retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->ibg_new * rd->flexbg_size, &buf); if (retval) @@ -427,15 +514,26 @@ errcode_t change_super_and_bgd(realloc_data *rd) blk = ext2fs_inode_table_loc(rd->fs, grp); if (used_ibg > 0) { - retval = io_channel_read_blk64(rd->fs->io, blk, min(used_ibg, rd->ibg_new), - buf + i*rd->ibg_new*EXT2_BLOCK_SIZE(rd->fs->super)); + inode_buf = buf + i*rd->ibg_new*EXT2_BLOCK_SIZE(rd->fs->super); + retval = io_channel_read_blk64(rd->fs->io, blk, min(used_ibg, rd->ibg_new), inode_buf); if (retval) goto out; if (used_ig < rd->ig_new) { - memset(buf + i*rd->ibg_new*EXT2_BLOCK_SIZE(rd->fs->super) + - EXT2_INODE_SIZE(rd->fs->super) * used_ig, 0, - EXT2_INODE_SIZE(rd->fs->super) * (rd->ig_new - used_ig)); + memset(inode_buf + EXT2_INODE_SIZE(rd->fs->super) * used_ig, + 0, EXT2_INODE_SIZE(rd->fs->super) * (rd->ig_new - used_ig)); + } + if (ext2fs_has_feature_metadata_csum(rd->fs->super)) + { + for (inum = 0; inum < used_ig || inum < rd->ig_new; inum++) + { + retval = ext2fs_inode_csum_set( + rd->fs, 1 + rd->ig_new*grp + inum, + inode_buf + EXT2_INODE_SIZE(rd->fs->super) * inum + ); + if (retval) + goto out; + } } } } @@ -683,6 +781,12 @@ errcode_t do_realloc(realloc_data *rd) { goto out; } +/* printf("Phase %d: Fixing all directory checksums\n", phase++); + retval = fix_dirent_csums(rd); + if (retval) + { + goto out; + }*/ out: if (rd->new_itable_loc) {