Fix new algorithm; works now!

master
Vitaliy Filippov 2014-01-09 21:29:10 +00:00
parent 2546396c10
commit 07da5e71d3
1 changed files with 33 additions and 17 deletions

View File

@ -22,9 +22,7 @@
/** /**
* TODO bigalloc compatibility * TODO bigalloc compatibility
* TODO write some tests: for inode moving (image with many files), * TODO write some tests
* for block moving, including extent blocks (one sparse file with many extents),
* for block moving between different groups
* *
* The theory isn't that hard: * The theory isn't that hard:
* 1) Determine where we want to move the inode tables: * 1) Determine where we want to move the inode tables:
@ -64,6 +62,17 @@
* also using e2patch utility. * also using e2patch utility.
*/ */
/**
* Need tests for:
* - both ext2 and ext4 filesystem images
* - inode moving: FS image with many files
* - block moving, including extent blocks: big sparse file with many extents
* - block moving between different groups
* - reallocation (both shrink and grow) in case of big flex_bg when inode
* tables don't fit into single block group
* - non-optimal reallocation, i.e. when inode block count doesn't change
*/
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
@ -241,8 +250,8 @@ out:
} }
/** /**
* Move data blocks from after the end of each block group inode table * Move data blocks from the new place for each block group inode table
* so the tables can be grown * so the tables can be grown or moved.
*/ */
errcode_t extend_move_blocks(realloc_data *rd) errcode_t extend_move_blocks(realloc_data *rd)
{ {
@ -332,6 +341,7 @@ errcode_t change_super_and_bgd(realloc_data *rd)
{ {
goto out; goto out;
} }
// First mark/unmark inode table blocks (mark and unmark in separate passes)
for (grp = 0; grp < rd->fs->group_desc_count; grp++) for (grp = 0; grp < rd->fs->group_desc_count; grp++)
{ {
for (i = 0, blk = ext2fs_inode_table_loc(rd->fs, grp); i < rd->ibg_old; i++, blk++) for (i = 0, blk = ext2fs_inode_table_loc(rd->fs, grp); i < rd->ibg_old; i++, blk++)
@ -343,7 +353,13 @@ errcode_t change_super_and_bgd(realloc_data *rd)
{ {
for (i = 0, blk = rd->new_itable_loc[grp]; i < rd->ibg_new; i++, blk++) for (i = 0, blk = rd->new_itable_loc[grp]; i < rd->ibg_new; i++, blk++)
{ {
ext2fs_block_alloc_stats2(rd->fs, blk, -1); if (ext2fs_test_block_bitmap2(rd->fs->block_map, blk))
{
printf("BUG: Block %lld (suited for group %u inode table) is still allocated\n", blk, grp);
retval = ENOSPC;
goto out;
}
ext2fs_block_alloc_stats2(rd->fs, blk, +1);
} }
} }
for (grp = 0; grp < rd->fs->group_desc_count; grp++) for (grp = 0; grp < rd->fs->group_desc_count; grp++)
@ -411,7 +427,6 @@ errcode_t change_super_and_bgd(realloc_data *rd)
rd->fs->write_bitmaps = NULL; rd->fs->write_bitmaps = NULL;
// Explicitly set 'overwrite backup superblocks' flag // Explicitly set 'overwrite backup superblocks' flag
rd->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY; rd->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
ext2fs_free_blocks_count_add(rd->fs->super, rd->fs->group_desc_count * (rd->ibg_old - rd->ibg_new));
rd->fs->super->s_free_inodes_count += rd->fs->group_desc_count * (rd->ig_new - rd->ig_old); rd->fs->super->s_free_inodes_count += rd->fs->group_desc_count * (rd->ig_new - rd->ig_old);
rd->fs->super->s_inodes_per_group = rd->ig_new; rd->fs->super->s_inodes_per_group = rd->ig_new;
rd->fs->super->s_inodes_count = rd->fs->group_desc_count * rd->ig_new; rd->fs->super->s_inodes_count = rd->fs->group_desc_count * rd->ig_new;
@ -526,6 +541,7 @@ errcode_t do_realloc(realloc_data *rd)
{ {
__u32 ig_round; __u32 ig_round;
errcode_t retval; errcode_t retval;
int phase = 1;
rd->ig_old = EXT2_INODES_PER_GROUP(rd->fs->super); rd->ig_old = EXT2_INODES_PER_GROUP(rd->fs->super);
rd->ig_new = rd->new_inode_count / rd->fs->group_desc_count; rd->ig_new = rd->new_inode_count / rd->fs->group_desc_count;
// inodes-per-group must be a multiple of 8 so each byte of inode bitmap is filled // inodes-per-group must be a multiple of 8 so each byte of inode bitmap is filled
@ -565,7 +581,7 @@ errcode_t do_realloc(realloc_data *rd)
rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count); rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count);
return ENOENT; return ENOENT;
} }
printf("Phase 1: Moving inodes out of the way\n"); printf("Phase %d: Moving inodes out of the way\n", phase++);
retval = shrink_move_inodes(rd); retval = shrink_move_inodes(rd);
if (retval) if (retval)
{ {
@ -582,25 +598,25 @@ errcode_t do_realloc(realloc_data *rd)
required_blocks, ext2fs_free_blocks_count(rd->fs->super)); required_blocks, ext2fs_free_blocks_count(rd->fs->super));
return ENOENT; return ENOENT;
} }
printf("Phase 1: Moving data blocks out of the way\n");
retval = extend_move_blocks(rd);
if (retval)
{
return retval;
}
} }
else else if (rd->ibg_new == rd->ibg_old)
{ {
printf("The requested number of inodes is equal to current\n"); printf("The requested number of inodes is equal to current\n");
return 0; return 0;
} }
printf("Phase 2: Changing all inode numbers\n"); printf("Phase %d: Moving data blocks out of the way\n", phase++);
retval = extend_move_blocks(rd);
if (retval)
{
return retval;
}
printf("Phase %d: Changing all inode numbers\n", phase++);
retval = change_inode_numbers(rd); retval = change_inode_numbers(rd);
if (retval) if (retval)
{ {
return retval; return retval;
} }
printf("Phase 3: Adjusting superblock and block group descriptors\n"); printf("Phase %d: Adjusting superblock and block group descriptors\n", phase++);
retval = change_super_and_bgd(rd); retval = change_super_and_bgd(rd);
if (retval) if (retval)
{ {