Remap blocks before moving inode tables (fixes big flex_bg extend),

check blocks to move even when shrinking inode tables (fixes big flex_bg shrink),
mark inode tables during allocation (fixes bigalloc shrink)
master
Vitaliy Filippov 2016-09-25 20:22:30 +03:00
parent 152890aa45
commit f58c260dc4
1 changed files with 67 additions and 30 deletions

View File

@ -367,9 +367,11 @@ static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size)
* 4) block_mover(): move blocks out of the way as usual * 4) block_mover(): move blocks out of the way as usual
* 5) inodes_to_move(): when shrinking inode tables, move inodes from the end * 5) inodes_to_move(): when shrinking inode tables, move inodes from the end
* of each group's inode table (still operating on old fs inode tables). * of each group's inode table (still operating on old fs inode tables).
* rewrite blocks used by inodes. * it would be possible to rewrite blocks on step 7, but we need to read
* extents, and they may be overwritten by inode tables on step 6.
* so, rewrite blocks used by inodes here!
* 6) move_inode_tables(): move inode tables * 6) move_inode_tables(): move inode tables
* 7) inode_scan_and_fix(): rewrite all extent checksums, extattr and ACL checksums * 7) inode_scan_and_fix(): rewrite all inode, extent, extattr and ACL checksums
* 8) inode_ref_fix(): translate inode numbers (operating on new fs inode tables) * 8) inode_ref_fix(): translate inode numbers (operating on new fs inode tables)
*/ */
static int set_inode_count(ext2_filsys fs, __u32 new_inodes) static int set_inode_count(ext2_filsys fs, __u32 new_inodes)
@ -1366,17 +1368,17 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
if (retval) { if (retval) {
return retval; return retval;
} }
// If we're extending inode tables, we need to move some blocks away ext2fs_mark_block_bitmap_range2(empty_bmap,
if (rfs->old_fs->inode_blocks_per_group < fs->inode_blocks_per_group) { ext2fs_inode_table_loc(fs, g), fs->inode_blocks_per_group);
group_blk = ext2fs_inode_table_loc(fs, g)+fs->inode_blocks_per_group; // We may need to move some blocks away (mainly if extending inode tables)
for (blk = ext2fs_inode_table_loc(fs, g); blk < group_blk; blk++) { group_blk = ext2fs_inode_table_loc(fs, g)+fs->inode_blocks_per_group;
if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) && for (blk = ext2fs_inode_table_loc(fs, g); blk < group_blk; blk++) {
!ext2fs_test_block_bitmap2(meta_bmap, blk)) { if (ext2fs_test_block_bitmap2(old_fs->block_map, blk) &&
ext2fs_mark_block_bitmap2(rfs->move_blocks, blk); !ext2fs_test_block_bitmap2(meta_bmap, blk)) {
rfs->needed_blocks++; ext2fs_mark_block_bitmap2(rfs->move_blocks, blk);
} rfs->needed_blocks++;
ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
} }
ext2fs_mark_block_bitmap2(rfs->reserve_blocks, blk);
} }
} }
ext2fs_free_block_bitmap(empty_bmap); ext2fs_free_block_bitmap(empty_bmap);
@ -1941,7 +1943,7 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
} }
} }
if (pb->is_dir) { if (pb->is_dir && fs->dblist) {
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino, retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
block, (int) blockcnt); block, (int) blockcnt);
if (retval) { if (retval) {
@ -2084,18 +2086,22 @@ static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)),
static errcode_t inodes_to_move(ext2_resize_t rfs) static errcode_t inodes_to_move(ext2_resize_t rfs)
{ {
struct process_block_struct pb;
ext2_ino_t ino, new_inode, tr_ino; ext2_ino_t ino, new_inode, tr_ino;
struct ext2_inode *inode = NULL; struct ext2_inode *inode = NULL;
ext2_inode_scan scan = NULL; ext2_inode_scan scan = NULL;
errcode_t retval; errcode_t retval;
dgrp_t g, old_g; dgrp_t g, old_g;
char *block_buf = 0;
ext2_ino_t start_to_move; ext2_ino_t start_to_move;
int inode_size; int inode_size;
int shrink_inodes = rfs->old_fs->inode_blocks_per_group > rfs->new_fs->inode_blocks_per_group; int shrink_inodes = rfs->old_fs->inode_blocks_per_group > rfs->new_fs->inode_blocks_per_group;
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
if ((rfs->old_fs->group_desc_count <= if ((rfs->old_fs->group_desc_count <=
rfs->new_fs->group_desc_count) && rfs->new_fs->group_desc_count) &&
!shrink_inodes) !rfs->bmap &&
!change_inodes)
return 0; return 0;
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan); retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
@ -2115,12 +2121,18 @@ static errcode_t inodes_to_move(ext2_resize_t rfs)
} }
} }
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
if (retval) goto errout;
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super); inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
inode = malloc(inode_size); inode = malloc(inode_size);
if (!inode) { if (!inode) {
retval = ENOMEM; retval = ENOMEM;
goto errout; goto errout;
} }
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
/* /*
* First, copy all of the inodes that need to be moved * First, copy all of the inodes that need to be moved
@ -2179,12 +2191,43 @@ static errcode_t inodes_to_move(ext2_resize_t rfs)
goto errout; goto errout;
} }
ext2fs_add_extent_entry(rfs->imap, ino, new_inode); ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
// continue with rewritten inode number
ino = new_inode;
}
/*
* Update inodes to point to new blocks.
*/
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) && rfs->bmap) {
pb.changed = 0;
pb.ino = ino;
pb.old_ino = ino; // FIXME debug output will show translated inodes
pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
retval = ext2fs_block_iterate3(rfs->old_fs,
ino, 0, block_buf,
process_block, &pb);
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
if (retval)
goto errout;
if (pb.error) {
retval = pb.error;
goto errout;
}
} }
} }
errout: errout:
if (rfs->bmap) {
ext2fs_free_extent_table(rfs->bmap);
rfs->bmap = 0;
}
if (scan) if (scan)
ext2fs_close_inode_scan(scan); ext2fs_close_inode_scan(scan);
if (block_buf)
ext2fs_free_mem(&block_buf);
free(inode); free(inode);
return retval; return retval;
} }
@ -2198,13 +2241,11 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
errcode_t retval; errcode_t retval;
dgrp_t g; dgrp_t g;
char *block_buf = 0; char *block_buf = 0;
ext2_ino_t start_to_move;
int inode_size; int inode_size;
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group; int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
if ((rfs->old_fs->group_desc_count <= if ((rfs->old_fs->group_desc_count <=
rfs->new_fs->group_desc_count) && rfs->new_fs->group_desc_count) &&
!rfs->bmap &&
!change_inodes) !change_inodes)
return 0; return 0;
@ -2225,15 +2266,15 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
goto errout; goto errout;
} }
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs); ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super); inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
inode = malloc(inode_size); inode = malloc(inode_size);
if (!inode) { if (!inode) {
retval = ENOMEM; retval = ENOMEM;
goto errout; goto errout;
} }
pb.rfs = rfs;
pb.inode = inode;
pb.error = 0;
/* /*
* First, copy all of the inodes that need to be moved * First, copy all of the inodes that need to be moved
* elsewhere in the inode table * elsewhere in the inode table
@ -2276,12 +2317,10 @@ remap_blocks:
} }
/* /*
* Update inodes to point to new blocks; schedule directory * Schedule directory blocks for inode remapping. Need to write out dir blocks
* blocks for inode remapping. Need to write out dir blocks
* with new inode numbers if we have metadata_csum enabled. * with new inode numbers if we have metadata_csum enabled.
*/ */
if (ext2fs_inode_has_valid_blocks2(rfs->new_fs, inode) && if (ext2fs_inode_has_valid_blocks2(rfs->new_fs, inode) && pb.is_dir) {
(rfs->bmap || pb.is_dir)) {
pb.ino = ino; pb.ino = ino;
pb.old_ino = ino; // FIXME: Debug output will show translated inodes pb.old_ino = ino; // FIXME: Debug output will show translated inodes
pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL; pb.has_extents = inode->i_flags & EXT4_EXTENTS_FL;
@ -2296,8 +2335,7 @@ remap_blocks:
retval = pb.error; retval = pb.error;
goto errout; goto errout;
} }
} else if ((inode->i_flags & EXT4_INLINE_DATA_FL) && } else if ((inode->i_flags & EXT4_INLINE_DATA_FL) && pb.is_dir) {
(rfs->bmap || pb.is_dir)) {
/* inline data dir; update it too */ /* inline data dir; update it too */
retval = ext2fs_add_dir_block2(rfs->new_fs->dblist, retval = ext2fs_add_dir_block2(rfs->new_fs->dblist,
tr_ino, 0, 0); tr_ino, 0, 0);
@ -2309,10 +2347,6 @@ remap_blocks:
errout: errout:
reset_com_err_hook(); reset_com_err_hook();
if (rfs->bmap) {
ext2fs_free_extent_table(rfs->bmap);
rfs->bmap = 0;
}
if (scan) if (scan)
ext2fs_close_inode_scan(scan); ext2fs_close_inode_scan(scan);
if (block_buf) if (block_buf)
@ -2360,10 +2394,13 @@ static errcode_t move_inode_tables(ext2_resize_t rfs)
ext2fs_bg_free_inodes_count(rfs->new_fs, g) + new_ipg - old_ipg); ext2fs_bg_free_inodes_count(rfs->new_fs, g) + new_ipg - old_ipg);
ext2fs_group_desc_csum_set(rfs->new_fs, g); ext2fs_group_desc_csum_set(rfs->new_fs, g);
} }
printf("g%u = %u->%u free=%u unused=%u\n", g, printf("g%u = [%u?] %u->%u free=%u->%u unused=%u->%u\n", g,
g > 0 ? ext2fs_inode_table_loc(rfs->old_fs, g-1)+old_ibg : 0,
ext2fs_inode_table_loc(rfs->old_fs, g), ext2fs_inode_table_loc(rfs->old_fs, g),
ext2fs_inode_table_loc(rfs->new_fs, g), ext2fs_inode_table_loc(rfs->new_fs, g),
ext2fs_bg_free_inodes_count(rfs->old_fs, g),
ext2fs_bg_free_inodes_count(rfs->new_fs, g), ext2fs_bg_free_inodes_count(rfs->new_fs, g),
ext2fs_bg_itable_unused(rfs->old_fs, g),
ext2fs_bg_itable_unused(rfs->new_fs, g)); ext2fs_bg_itable_unused(rfs->new_fs, g));
if ((change_inodes || ext2fs_inode_table_loc(rfs->new_fs, g) != ext2fs_inode_table_loc(rfs->old_fs, g)) && if ((change_inodes || ext2fs_inode_table_loc(rfs->new_fs, g) != ext2fs_inode_table_loc(rfs->old_fs, g)) &&
(!ext2fs_has_group_desc_csum(rfs->new_fs) || (!ext2fs_has_group_desc_csum(rfs->new_fs) ||