mirror of https://github.com/vitalif/e2fsprogs
Split inode_scan_and_fix into two parts.
- Basic extend and shrink works - Extend on bigalloc fs works - Shrink on bigalloc fs gives errors - Extend on big flex_bg gives errorsmaster
parent
63039f4bac
commit
152890aa45
|
@ -45,6 +45,7 @@ static void fix_uninit_block_bitmaps(ext2_filsys fs);
|
|||
static errcode_t adjust_superblock(ext2_resize_t rfs, blk64_t new_size);
|
||||
static errcode_t blocks_to_move(ext2_resize_t rfs);
|
||||
static errcode_t block_mover(ext2_resize_t rfs);
|
||||
static errcode_t inodes_to_move(ext2_resize_t rfs);
|
||||
static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
|
||||
static errcode_t inode_ref_fix(ext2_resize_t rfs);
|
||||
static errcode_t move_itables(ext2_resize_t rfs);
|
||||
|
@ -53,7 +54,7 @@ static errcode_t fix_resize_inode(ext2_filsys fs);
|
|||
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
|
||||
static errcode_t fix_sb_journal_backup(ext2_filsys fs);
|
||||
static errcode_t mark_table_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap bmap);
|
||||
ext2fs_block_bitmap bmap, int skip_inode_tables);
|
||||
static errcode_t clear_sparse_super2_last_group(ext2_resize_t rfs);
|
||||
static errcode_t reserve_sparse_super2_last_group(ext2_resize_t rfs,
|
||||
ext2fs_block_bitmap meta_bmap);
|
||||
|
@ -189,8 +190,8 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int fla
|
|||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "inode_scan_and_fix", fs->io);
|
||||
retval = inode_scan_and_fix(rfs);
|
||||
init_resource_track(&rtrack, "inodes_to_move", fs->io);
|
||||
retval = inodes_to_move(rfs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
@ -201,6 +202,12 @@ errcode_t resize_fs(ext2_filsys fs, blk64_t *new_size, __u32 new_inodes, int fla
|
|||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "inode_scan_and_fix", fs->io);
|
||||
retval = inode_scan_and_fix(rfs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
print_resource_track(rfs, &rtrack, fs->io);
|
||||
|
||||
init_resource_track(&rtrack, "inode_ref_fix", fs->io);
|
||||
retval = inode_ref_fix(rfs);
|
||||
if (retval)
|
||||
|
@ -358,10 +365,12 @@ static errcode_t resize_group_descriptors(ext2_resize_t rfs, blk64_t new_size)
|
|||
* 3) blocks_to_move(): allocate new inode tables and, when extending inode tables,
|
||||
* mark extra blocks needed for new inode tables as 'blocks to move'
|
||||
* 4) block_mover(): move blocks out of the way as usual
|
||||
* 5) inode_scan_and_fix(): when shrinking inode tables, move inodes from the end
|
||||
* of each group's inode table (still operating on old fs inode tables)
|
||||
* 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).
|
||||
* rewrite blocks used by inodes.
|
||||
* 6) move_inode_tables(): move inode tables
|
||||
* 7) inode_ref_fix(): translate inode numbers (operating on new fs inode tables)
|
||||
* 7) inode_scan_and_fix(): rewrite all extent checksums, extattr and ACL checksums
|
||||
* 8) inode_ref_fix(): translate inode numbers (operating on new fs inode tables)
|
||||
*/
|
||||
static int set_inode_count(ext2_filsys fs, __u32 new_inodes)
|
||||
{
|
||||
|
@ -683,7 +692,7 @@ static errcode_t free_gdp_blocks(ext2_filsys fs,
|
|||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = mark_table_blocks(fs, bg_map);
|
||||
retval = mark_table_blocks(fs, bg_map, 0);
|
||||
if (retval)
|
||||
goto out;
|
||||
}
|
||||
|
@ -1050,7 +1059,7 @@ retry:
|
|||
* number of the block group descriptors.
|
||||
*/
|
||||
if (reserve_blocks)
|
||||
mark_table_blocks(fs, reserve_blocks);
|
||||
mark_table_blocks(fs, reserve_blocks, 0);
|
||||
|
||||
errout:
|
||||
return (retval);
|
||||
|
@ -1184,7 +1193,7 @@ errout:
|
|||
* filesystem meta-data blocks.
|
||||
*/
|
||||
static errcode_t mark_table_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap bmap)
|
||||
ext2fs_block_bitmap bmap, int skip_inode_tables)
|
||||
{
|
||||
dgrp_t i;
|
||||
blk64_t blk;
|
||||
|
@ -1195,10 +1204,12 @@ static errcode_t mark_table_blocks(ext2_filsys fs,
|
|||
/*
|
||||
* Mark the blocks used for the inode table
|
||||
*/
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk)
|
||||
ext2fs_mark_block_bitmap_range2(bmap, blk,
|
||||
fs->inode_blocks_per_group);
|
||||
if (!skip_inode_tables) {
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk)
|
||||
ext2fs_mark_block_bitmap_range2(bmap, blk,
|
||||
fs->inode_blocks_per_group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark block used for the block bitmap
|
||||
|
@ -1322,7 +1333,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = mark_table_blocks(old_fs, meta_bmap);
|
||||
retval = mark_table_blocks(old_fs, meta_bmap, 0);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
@ -1338,6 +1349,10 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
|
|||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
retval = mark_table_blocks(fs, empty_bmap, 1);
|
||||
if (retval) {
|
||||
return retval;
|
||||
}
|
||||
if (EXT2_HAS_INCOMPAT_FEATURE(fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
|
||||
&& fs->super->s_log_groups_per_flex) {
|
||||
flexbg_size = 1 << fs->super->s_log_groups_per_flex;
|
||||
|
@ -1465,7 +1480,7 @@ static errcode_t blocks_to_move(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
goto errout;
|
||||
|
||||
retval = mark_table_blocks(fs, new_meta_bmap);
|
||||
retval = mark_table_blocks(fs, new_meta_bmap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
@ -1973,27 +1988,27 @@ static errcode_t migrate_ea_block(ext2_resize_t rfs, ext2_ino_t ino,
|
|||
errcode_t err = 0;
|
||||
|
||||
/* No EA block or no remapping? Quit early. */
|
||||
if (ext2fs_file_acl_block(rfs->old_fs, inode) == 0 || !rfs->bmap)
|
||||
if (ext2fs_file_acl_block(rfs->new_fs, inode) == 0 || !rfs->bmap)
|
||||
return 0;
|
||||
new_block = extent_translate(rfs->old_fs, rfs->bmap,
|
||||
ext2fs_file_acl_block(rfs->old_fs, inode));
|
||||
new_block = extent_translate(rfs->new_fs, rfs->bmap,
|
||||
ext2fs_file_acl_block(rfs->new_fs, inode));
|
||||
if (new_block == 0)
|
||||
return 0;
|
||||
|
||||
/* Set the new ACL block */
|
||||
ext2fs_file_acl_block_set(rfs->old_fs, inode, new_block);
|
||||
ext2fs_file_acl_block_set(rfs->new_fs, inode, new_block);
|
||||
|
||||
/* Update checksum */
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super)) {
|
||||
err = ext2fs_get_mem(rfs->old_fs->blocksize, &buf);
|
||||
err = ext2fs_get_mem(rfs->new_fs->blocksize, &buf);
|
||||
if (err)
|
||||
return err;
|
||||
rfs->old_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
err = ext2fs_read_ext_attr3(rfs->old_fs, new_block, buf, ino);
|
||||
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
err = ext2fs_read_ext_attr3(rfs->new_fs, new_block, buf, ino);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_write_ext_attr3(rfs->old_fs, new_block, buf, ino);
|
||||
err = ext2fs_write_ext_attr3(rfs->new_fs, new_block, buf, ino);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
@ -2067,35 +2082,25 @@ static void quiet_com_err_proc(const char *whoami EXT2FS_ATTR((unused)),
|
|||
#define TRANSLATE_IPG(ino,old_fs,new_fs) (1 + (((ino)-1) % (old_fs)->super->s_inodes_per_group) + \
|
||||
((ino)-1) / (old_fs)->super->s_inodes_per_group * (new_fs)->super->s_inodes_per_group)
|
||||
|
||||
static errcode_t inode_scan_and_fix(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;
|
||||
struct ext2_inode *inode = NULL;
|
||||
ext2_inode_scan scan = NULL;
|
||||
errcode_t retval;
|
||||
dgrp_t g;
|
||||
char *block_buf = 0;
|
||||
dgrp_t g, old_g;
|
||||
ext2_ino_t start_to_move;
|
||||
int inode_size;
|
||||
int shrink_inodes = rfs->old_fs->inode_blocks_per_group > rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if ((rfs->old_fs->group_desc_count <=
|
||||
rfs->new_fs->group_desc_count) &&
|
||||
!rfs->bmap &&
|
||||
!shrink_inodes)
|
||||
return 0;
|
||||
|
||||
set_com_err_hook(quiet_com_err_proc);
|
||||
|
||||
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
|
||||
if (retval) goto errout;
|
||||
|
||||
retval = ext2fs_init_dblist(rfs->new_fs, 0);
|
||||
if (retval) goto errout;
|
||||
retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
|
||||
if (retval) goto errout;
|
||||
|
||||
start_to_move = (rfs->new_fs->group_desc_count *
|
||||
rfs->old_fs->super->s_inodes_per_group);
|
||||
for (ino = start_to_move; ino <= rfs->old_fs->group_desc_count * rfs->old_fs->super->s_inodes_per_group; ino++) {
|
||||
|
@ -2110,23 +2115,13 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
|||
}
|
||||
}
|
||||
|
||||
if (rfs->progress) {
|
||||
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
||||
0, rfs->old_fs->group_desc_count);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
|
||||
pb.rfs = rfs;
|
||||
pb.inode = inode;
|
||||
pb.error = 0;
|
||||
new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
|
||||
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
|
||||
inode = malloc(inode_size);
|
||||
if (!inode) {
|
||||
retval = ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* First, copy all of the inodes that need to be moved
|
||||
* elsewhere in the inode table
|
||||
|
@ -2140,64 +2135,142 @@ static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
|||
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
|
||||
continue; /* inode not in use */
|
||||
|
||||
new_inode = ino;
|
||||
if (ino > start_to_move ||
|
||||
(shrink_inodes && (ino-1) % rfs->old_fs->super->s_inodes_per_group >= rfs->new_fs->super->s_inodes_per_group))
|
||||
{
|
||||
/*
|
||||
* Find a new inode. Now that extents and directory blocks
|
||||
* are tied to the inode number through the checksum, we must
|
||||
* set up the new inode before we start rewriting blocks.
|
||||
*/
|
||||
retval = ext2fs_new_inode(rfs->old_fs, 0, 0, 0, &new_inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/* Translate inode number according to new inodes_per_group */
|
||||
tr_ino = TRANSLATE_IPG(new_inode, rfs->old_fs, rfs->new_fs);
|
||||
|
||||
old_g = ext2fs_group_of_ino(rfs->old_fs, ino);
|
||||
ext2fs_inode_alloc_stats2(rfs->old_fs, new_inode, +1, LINUX_S_ISDIR(inode->i_mode));
|
||||
if (old_g < rfs->new_fs->group_desc_count)
|
||||
{
|
||||
/* Adjust alloc stats for moved inode to have correct free_inodes_count */
|
||||
ext2fs_bg_free_inodes_count_set(rfs->new_fs, old_g, ext2fs_bg_free_inodes_count(rfs->new_fs, old_g) + 1);
|
||||
if (LINUX_S_ISDIR(inode->i_mode))
|
||||
ext2fs_bg_used_dirs_count_set(rfs->new_fs, old_g, ext2fs_bg_used_dirs_count(rfs->new_fs, old_g) - 1);
|
||||
ext2fs_group_desc_csum_set(rfs->new_fs, old_g);
|
||||
rfs->new_fs->super->s_free_inodes_count++;
|
||||
}
|
||||
ext2fs_inode_alloc_stats2(rfs->new_fs, tr_ino, +1, LINUX_S_ISDIR(inode->i_mode));
|
||||
inode->i_ctime = time(0);
|
||||
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode, inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode moved %u->%u\n", ino, new_inode);
|
||||
#endif
|
||||
|
||||
if (!rfs->imap) {
|
||||
retval = ext2fs_create_extent_table(&rfs->imap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
|
||||
}
|
||||
}
|
||||
|
||||
errout:
|
||||
if (scan)
|
||||
ext2fs_close_inode_scan(scan);
|
||||
free(inode);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
||||
{
|
||||
struct process_block_struct pb;
|
||||
ext2_ino_t ino, tr_ino;
|
||||
struct ext2_inode *inode = NULL;
|
||||
ext2_inode_scan scan = NULL;
|
||||
errcode_t retval;
|
||||
dgrp_t g;
|
||||
char *block_buf = 0;
|
||||
ext2_ino_t start_to_move;
|
||||
int inode_size;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if ((rfs->old_fs->group_desc_count <=
|
||||
rfs->new_fs->group_desc_count) &&
|
||||
!rfs->bmap &&
|
||||
!change_inodes)
|
||||
return 0;
|
||||
|
||||
set_com_err_hook(quiet_com_err_proc);
|
||||
|
||||
retval = ext2fs_open_inode_scan(rfs->new_fs, 0, &scan);
|
||||
if (retval) goto errout;
|
||||
|
||||
retval = ext2fs_init_dblist(rfs->new_fs, 0);
|
||||
if (retval) goto errout;
|
||||
retval = ext2fs_get_array(rfs->new_fs->blocksize, 3, &block_buf);
|
||||
if (retval) goto errout;
|
||||
|
||||
if (rfs->progress) {
|
||||
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
||||
0, rfs->new_fs->group_desc_count);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
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 = malloc(inode_size);
|
||||
if (!inode) {
|
||||
retval = ENOMEM;
|
||||
goto errout;
|
||||
}
|
||||
/*
|
||||
* First, copy all of the inodes that need to be moved
|
||||
* elsewhere in the inode table
|
||||
*/
|
||||
while (1) {
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval) goto errout;
|
||||
if (!ino)
|
||||
break;
|
||||
|
||||
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
|
||||
continue; /* inode not in use */
|
||||
|
||||
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
|
||||
pb.changed = 0;
|
||||
pb.changed = change_inodes;
|
||||
|
||||
/* Remap EA block */
|
||||
retval = migrate_ea_block(rfs, ino, inode, &pb.changed);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
new_inode = ino;
|
||||
if (ino <= start_to_move &&
|
||||
(!shrink_inodes || (ino-1) % rfs->old_fs->super->s_inodes_per_group < rfs->new_fs->super->s_inodes_per_group))
|
||||
goto remap_blocks; /* Don't need to move inode. */
|
||||
|
||||
/*
|
||||
* Find a new inode. Now that extents and directory blocks
|
||||
* are tied to the inode number through the checksum, we must
|
||||
* set up the new inode before we start rewriting blocks.
|
||||
*/
|
||||
retval = ext2fs_new_inode(rfs->old_fs, 0, 0, 0, &new_inode);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/* Translate inode number according to new inodes_per_group */
|
||||
tr_ino = TRANSLATE_IPG(new_inode, rfs->old_fs, rfs->new_fs);
|
||||
|
||||
ext2fs_inode_alloc_stats2(rfs->new_fs, tr_ino, +1, pb.is_dir);
|
||||
inode->i_ctime = time(0);
|
||||
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
|
||||
inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
pb.changed = 0;
|
||||
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode moved %u->%u\n", ino, new_inode);
|
||||
#endif
|
||||
if (!rfs->imap) {
|
||||
retval = ext2fs_create_extent_table(&rfs->imap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
|
||||
|
||||
remap_blocks:
|
||||
if (pb.changed)
|
||||
retval = ext2fs_write_inode_full(rfs->old_fs,
|
||||
new_inode,
|
||||
retval = ext2fs_write_inode_full(rfs->new_fs,
|
||||
ino,
|
||||
inode, inode_size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
/* Rewrite extent block checksums with new inode number */
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->old_fs->super) &&
|
||||
if (ext2fs_has_feature_metadata_csum(rfs->new_fs->super) &&
|
||||
(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;
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = rewrite_extents(rfs->new_fs, ino);
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
@ -2207,16 +2280,16 @@ remap_blocks:
|
|||
* blocks for inode remapping. Need to write out dir blocks
|
||||
* with new inode numbers if we have metadata_csum enabled.
|
||||
*/
|
||||
if (ext2fs_inode_has_valid_blocks2(rfs->old_fs, inode) &&
|
||||
if (ext2fs_inode_has_valid_blocks2(rfs->new_fs, inode) &&
|
||||
(rfs->bmap || pb.is_dir)) {
|
||||
pb.ino = new_inode;
|
||||
pb.old_ino = ino;
|
||||
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,
|
||||
new_inode, 0, block_buf,
|
||||
rfs->new_fs->flags |= EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
retval = ext2fs_block_iterate3(rfs->new_fs,
|
||||
ino, 0, block_buf,
|
||||
process_block, &pb);
|
||||
rfs->old_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
rfs->new_fs->flags &= ~EXT2_FLAG_IGNORE_CSUM_ERRORS;
|
||||
if (retval)
|
||||
goto errout;
|
||||
if (pb.error) {
|
||||
|
@ -2232,7 +2305,7 @@ remap_blocks:
|
|||
goto errout;
|
||||
}
|
||||
}
|
||||
io_channel_flush(rfs->old_fs->io);
|
||||
io_channel_flush(rfs->new_fs->io);
|
||||
|
||||
errout:
|
||||
reset_com_err_hook();
|
||||
|
@ -2250,27 +2323,58 @@ errout:
|
|||
|
||||
static errcode_t move_inode_tables(ext2_resize_t rfs)
|
||||
{
|
||||
dgrp_t g, end_g;
|
||||
dgrp_t g, end_g, group_count;
|
||||
dgrp_t move_start, move_count;
|
||||
__u32 old_ipg = rfs->old_fs->super->s_inodes_per_group;
|
||||
__u32 new_ipg = rfs->new_fs->super->s_inodes_per_group;
|
||||
__u32 old_ibg = rfs->old_fs->inode_blocks_per_group;
|
||||
__u32 new_ibg = rfs->new_fs->inode_blocks_per_group;
|
||||
int retval;
|
||||
blk64_t size;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group == rfs->new_fs->inode_blocks_per_group;
|
||||
blk64_t size, blk;
|
||||
int change_inodes = old_ibg != new_ibg;
|
||||
__u32 unused, ino, old_ino, i;
|
||||
ext2fs_block_bitmap meta_bmap = NULL;
|
||||
|
||||
size = rfs->old_fs->inode_blocks_per_group;
|
||||
size = size < rfs->new_fs->inode_blocks_per_group ? size : rfs->new_fs->inode_blocks_per_group;
|
||||
retval = ext2fs_allocate_block_bitmap(rfs->new_fs, _("meta-data blocks"), &meta_bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = mark_table_blocks(rfs->new_fs, meta_bmap, 1);
|
||||
|
||||
printf("inode blocks per group: %u to %u\n", old_ibg, new_ibg);
|
||||
size = old_ibg;
|
||||
size = size < new_ibg ? size : new_ibg;
|
||||
move_count = 0;
|
||||
for (g = 0; g < rfs->new_fs->group_desc_count; g++)
|
||||
group_count = rfs->new_fs->group_desc_count;
|
||||
group_count = group_count < rfs->old_fs->group_desc_count ? group_count : rfs->old_fs->group_desc_count;
|
||||
for (g = 0; g < group_count; g++)
|
||||
{
|
||||
if (change_inodes)
|
||||
{
|
||||
unused = ext2fs_bg_itable_unused(rfs->new_fs, g);
|
||||
if (new_ipg < old_ipg && unused < old_ipg-new_ipg)
|
||||
unused = 0;
|
||||
else
|
||||
unused = unused + new_ipg - old_ipg;
|
||||
ext2fs_bg_itable_unused_set(rfs->new_fs, g, unused);
|
||||
ext2fs_bg_free_inodes_count_set(rfs->new_fs, g,
|
||||
ext2fs_bg_free_inodes_count(rfs->new_fs, g) + new_ipg - old_ipg);
|
||||
ext2fs_group_desc_csum_set(rfs->new_fs, g);
|
||||
}
|
||||
printf("g%u = %u->%u free=%u unused=%u\n", g,
|
||||
ext2fs_inode_table_loc(rfs->old_fs, g),
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g),
|
||||
ext2fs_bg_free_inodes_count(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)) &&
|
||||
(!ext2fs_has_group_desc_csum(rfs->old_fs) ||
|
||||
!ext2fs_bg_flags_test(rfs->old_fs, g, EXT2_BG_INODE_UNINIT)))
|
||||
(!ext2fs_has_group_desc_csum(rfs->new_fs) ||
|
||||
!ext2fs_bg_flags_test(rfs->new_fs, g, EXT2_BG_INODE_UNINIT)))
|
||||
{
|
||||
move_count++;
|
||||
if (move_count == 1)
|
||||
move_start = g;
|
||||
// check for overlap
|
||||
if (g < rfs->new_fs->group_desc_count-1 &&
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g)+rfs->new_fs->inode_blocks_per_group > ext2fs_inode_table_loc(rfs->old_fs, g+1))
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g)+new_ibg > ext2fs_inode_table_loc(rfs->old_fs, g+1))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -2278,39 +2382,65 @@ static errcode_t move_inode_tables(ext2_resize_t rfs)
|
|||
if (move_count > 0)
|
||||
{
|
||||
end_g = g;
|
||||
for (g = move_start+move_count-1; g >= move_start; g--)
|
||||
for (g = move_start+move_count; g > move_start; g--)
|
||||
{
|
||||
retval = io_channel_read_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->old_fs, g), size, rfs->itable_buf);
|
||||
retval = io_channel_read_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->old_fs, g-1), size, rfs->itable_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = io_channel_write_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->new_fs, g), size, rfs->itable_buf);
|
||||
retval = io_channel_write_blk64(rfs->new_fs->io, ext2fs_inode_table_loc(rfs->new_fs, g-1), size, rfs->itable_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (rfs->new_fs->inode_blocks_per_group > rfs->old_fs->inode_blocks_per_group)
|
||||
if (new_ibg > old_ibg)
|
||||
{
|
||||
retval = ext2fs_zero_blocks2(rfs->new_fs,
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g)+rfs->old_fs->inode_blocks_per_group,
|
||||
rfs->new_fs->inode_blocks_per_group-rfs->old_fs->inode_blocks_per_group, NULL, NULL);
|
||||
ext2fs_inode_table_loc(rfs->new_fs, g-1)+old_ibg,
|
||||
new_ibg-old_ibg, NULL, NULL);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
blk = ext2fs_inode_table_loc(rfs->old_fs, g-1);
|
||||
for (i = 0; i < old_ibg; i++)
|
||||
if (!ext2fs_test_block_bitmap2(meta_bmap, blk+i))
|
||||
ext2fs_unmark_block_bitmap2(rfs->new_fs->block_map, blk+i);
|
||||
ext2fs_mark_block_bitmap_range2(rfs->new_fs->block_map, ext2fs_inode_table_loc(rfs->new_fs, g-1), new_ibg);
|
||||
}
|
||||
move_start = move_count = 0;
|
||||
g = end_g;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
if (old_ipg < new_ipg)
|
||||
{
|
||||
for (g = 0; g < group_count; g++)
|
||||
{
|
||||
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < old_ipg; i++, ino++, old_ino++)
|
||||
{
|
||||
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
|
||||
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
for (i = old_ipg, ino = 1 + new_ipg*g + old_ipg; i < new_ipg; i++, ino++)
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
}
|
||||
else if (old_ipg > new_ipg)
|
||||
{
|
||||
dgrp_t n;
|
||||
for (n = 0, g = group_count-1; n < group_count; n++, g--)
|
||||
{
|
||||
for (i = 0, old_ino = 1 + old_ipg*g, ino = 1 + new_ipg*g; i < new_ipg; i++, ino++, old_ino++)
|
||||
{
|
||||
if (ext2fs_test_inode_bitmap2(rfs->old_fs->inode_map, old_ino))
|
||||
ext2fs_mark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(rfs->new_fs->inode_map, ino);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext2fs_free_block_bitmap(meta_bmap);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2360,16 +2490,21 @@ static int check_and_change_inodes(ext2_ino_t dir,
|
|||
ret |= DIRENT_CHANGED;
|
||||
|
||||
if (!dirent->inode)
|
||||
{
|
||||
if (old_dir != dir)
|
||||
ret |= DIRENT_CHANGED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
new_inode = TRANSLATE_IPG(dirent->inode, is->rfs->new_fs, is->rfs->old_fs);
|
||||
new_inode = ext2fs_extent_translate(is->rfs->imap, new_inode);
|
||||
|
||||
new_inode = 0;
|
||||
if (is->rfs->imap)
|
||||
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
|
||||
if (!new_inode)
|
||||
new_inode = dirent->inode;
|
||||
new_inode = TRANSLATE_IPG(new_inode, is->rfs->old_fs, is->rfs->new_fs);
|
||||
if (new_inode == dirent->inode && old_dir == dir)
|
||||
return ret;
|
||||
|
||||
new_inode = TRANSLATE_IPG(dirent->inode, is->rfs->old_fs, is->rfs->new_fs);
|
||||
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
|
||||
printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
|
||||
|
@ -2395,8 +2530,9 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|||
{
|
||||
errcode_t retval;
|
||||
struct istruct is;
|
||||
int change_inodes = rfs->old_fs->inode_blocks_per_group != rfs->new_fs->inode_blocks_per_group;
|
||||
|
||||
if (!rfs->imap)
|
||||
if (!change_inodes && !rfs->imap)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -2432,7 +2568,8 @@ static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|||
is.max_dirs, is.max_dirs);
|
||||
|
||||
errout:
|
||||
ext2fs_free_extent_table(rfs->imap);
|
||||
if (rfs->imap)
|
||||
ext2fs_free_extent_table(rfs->imap);
|
||||
rfs->imap = 0;
|
||||
return retval;
|
||||
}
|
||||
|
@ -2488,7 +2625,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
|
|||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = mark_table_blocks(fs, new_bmap);
|
||||
retval = mark_table_blocks(fs, new_bmap, 0);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
@ -2600,7 +2737,7 @@ static errcode_t move_itables(ext2_resize_t rfs)
|
|||
goto errout;
|
||||
}
|
||||
}
|
||||
mark_table_blocks(fs, fs->block_map);
|
||||
mark_table_blocks(fs, fs->block_map, 0);
|
||||
ext2fs_flush(fs);
|
||||
#ifdef RESIZE2FS_DEBUG
|
||||
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
|
||||
|
|
Loading…
Reference in New Issue