fix inode checksums... but it also requires to fix directory checksums... so in fact it is better to just merge it in resize2fs...

master
Vitaliy Filippov 2016-09-15 21:42:06 +00:00
parent ceeb9c6cdc
commit bf188ee362
2 changed files with 118 additions and 7 deletions

View File

@ -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;

View File

@ -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)
{