Works on a VERY basic test case (shrink, no inode moving, no inode number change) with errors successfully corrected by fsck :-)))

master
Vitaliy Filippov 2013-12-27 23:14:21 +00:00
parent f58ece6d8c
commit a33f91e388
1 changed files with 63 additions and 67 deletions

View File

@ -122,6 +122,11 @@ int shrink_move_inodes(realloc_data *rd)
__u32 new_group;
ext2_ino_t ino, new_ino;
struct ext2_inode *inode = NULL;
ext2fs_read_inode_bitmap(rd->fs);
if (retval)
{
return retval;
}
retval = ext2fs_get_mem(inode_size, &inode);
if (retval)
{
@ -129,18 +134,18 @@ int shrink_move_inodes(realloc_data *rd)
}
for (group = 0; group < rd->fs->group_desc_count; group++)
{
for (i = rd->new_inodes_per_group; i < rd->fs->super->s_inodes_per_group; i++)
for (i = rd->new_inodes_per_group; i < EXT2_INODES_PER_GROUP(rd->fs->super); i++)
{
ino = 1 + group*rd->fs->super->s_inodes_per_group + i;
if (ext2fs_test_inode_bitmap(rd->fs->inode_map, ino))
ino = 1 + group*EXT2_INODES_PER_GROUP(rd->fs->super) + i;
if (ext2fs_test_inode_bitmap2(rd->fs->inode_map, ino))
{
// Inode is occupied and should be moved
new_group = group;
do
{
retval = ext2fs_find_first_zero_inode_bitmap2(rd->fs->inode_map,
1 + new_group*rd->fs->super->s_inodes_per_group,
1 + new_group*rd->fs->super->s_inodes_per_group+rd->new_inodes_per_group, &new_ino);
1 + new_group*EXT2_INODES_PER_GROUP(rd->fs->super),
1 + new_group*EXT2_INODES_PER_GROUP(rd->fs->super)+rd->new_inodes_per_group, &new_ino);
if (!retval)
{
break;
@ -196,17 +201,13 @@ static int change_inode_numbers_callback(ext2_ino_t dir, int entry,
int blocksize, char *buf, void *priv_data)
{
realloc_data *rd = priv_data;
char name[EXT2_NAME_LEN+1];
ext2_ino_t new_ino = realloc_search_inode_map(rd, dirent->inode);
if (!new_ino)
{
new_ino = dirent->inode;
}
new_ino = 1 + (new_ino-1)/rd->fs->super->s_inodes_per_group*rd->new_inodes_per_group +
(new_ino-1)%rd->fs->super->s_inodes_per_group;
strncpy(name, dirent->name, dirent->name_len & 0xff);
name[dirent->name_len & 0xff] = 0;
printf("%s: old %d, new %d\n", name, dirent->inode, new_ino);
new_ino = 1 + (new_ino-1)/EXT2_INODES_PER_GROUP(rd->fs->super)*rd->new_inodes_per_group +
(new_ino-1)%EXT2_INODES_PER_GROUP(rd->fs->super);
if (new_ino != dirent->inode)
{
dirent->inode = new_ino;
@ -220,53 +221,31 @@ static int change_inode_numbers_callback(ext2_ino_t dir, int entry,
*/
int change_inode_numbers(realloc_data *rd)
{
int j, retval;
dgrp_t grp;
blk64_t blk;
void *buf;
struct ext2_inode *inode;
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->fs->inode_blocks_per_group, &buf);
ext2_ino_t ino;
realloc_sort_inode_map(rd);
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
for (ino = 1; ino <= rd->fs->super->s_inodes_count; ino++)
{
// read inode table of a group
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
{
blk = ext2fs_inode_table_loc(rd->fs, grp);
retval = io_channel_read_blk64(rd->fs->io, blk, rd->fs->inode_blocks_per_group, buf);
if (retval)
{
break;
}
for (j = 0; j < rd->fs->super->s_inodes_per_group; j++)
{
inode = (struct ext2_inode*)(buf + EXT2_INODE_SIZE(rd->fs->super) * j);
if (inode->i_mode & S_IFDIR)
{
printf("Directory %d\n", 1+j+grp*rd->fs->super->s_inodes_per_group);
ext2fs_dir_iterate2(rd->fs, 1+j+grp*rd->fs->super->s_inodes_per_group, 0, 0, change_inode_numbers_callback, rd);
printf("\n");
}
}
}
ext2fs_dir_iterate2(rd->fs, ino, 0, 0, change_inode_numbers_callback, rd);
}
ext2fs_free_mem(&buf);
return 0;
}
/**
* If flex_bg is enabled, move inode tables so they are consecutive again
* 1) Move inode tables so they are consecutive again if flex_bg is enabled
* 2) Mark/unmark extra inode table blocks
* 3) Adjust superblock and block group descriptors
*/
int flex_bg_move_itables(realloc_data *rd)
int change_super_and_bgd(realloc_data *rd)
{
blk64_t it_start, blk;
dgrp_t grp, n_flex, last_grp;
int flexbg_size = 0, i, retval = 0;
void *buf = NULL;
ext2fs_flush(rd->fs);
ext2fs_read_block_bitmap(rd->fs);
if (rd->new_inode_blocks_per_group != rd->fs->inode_blocks_per_group)
{
// Move inode tables, if flex_bg is active
// Move inode tables if flex_bg is active
if (EXT2_HAS_INCOMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_INCOMPAT_FLEX_BG)
&& rd->fs->super->s_log_groups_per_flex)
{
@ -308,11 +287,25 @@ int flex_bg_move_itables(realloc_data *rd)
// Mark/unmark extra inode table blocks
if (rd->new_inode_blocks_per_group < rd->fs->inode_blocks_per_group)
{
ext2fs_unmark_block_bitmap_range(rd->fs->block_map, it_start+blk, (rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group)*flexbg_size);
ext2fs_unmark_block_bitmap_range2(rd->fs->block_map, it_start+blk, (rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group)*flexbg_size);
}
else
{
ext2fs_mark_block_bitmap_range(rd->fs->block_map, it_start+blk, (rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*flexbg_size);
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start+blk, (rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*flexbg_size);
}
// Change inode table locations and free block/inode counts
for (grp = n_flex*flexbg_size, i = 0; grp < last_grp; grp++, i++)
{
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
{
blk = it_start + rd->new_inode_blocks_per_group*i;
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
ext2fs_bg_free_blocks_count_set(rd->fs, grp, ext2fs_bg_free_blocks_count(rd->fs, grp) +
rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group);
ext2fs_bg_free_inodes_count_set(rd->fs, grp, ext2fs_bg_free_inodes_count(rd->fs, grp) +
rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
ext2fs_bg_itable_unused_set(rd->fs, grp, 0); // Is it correct?..
}
}
}
}
@ -326,16 +319,26 @@ int flex_bg_move_itables(realloc_data *rd)
it_start = ext2fs_inode_table_loc(rd->fs, grp);
if (rd->new_inode_blocks_per_group < rd->fs->inode_blocks_per_group)
{
ext2fs_unmark_block_bitmap_range(rd->fs->block_map, it_start, rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group);
ext2fs_unmark_block_bitmap_range2(rd->fs->block_map, it_start, rd->fs->inode_blocks_per_group-rd->new_inode_blocks_per_group);
}
else
{
ext2fs_mark_block_bitmap_range(rd->fs->block_map, it_start, rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start, rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
}
// Update free block/inode counts
ext2fs_bg_free_blocks_count_set(rd->fs, grp, ext2fs_bg_free_blocks_count(rd->fs, grp) +
rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group);
ext2fs_bg_free_inodes_count_set(rd->fs, grp, ext2fs_bg_free_inodes_count(rd->fs, grp) +
rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
ext2fs_bg_itable_unused_set(rd->fs, grp, 0); // Is it correct?..
}
}
}
}
ext2fs_free_blocks_count_add(rd->fs->super, rd->fs->group_desc_count * (rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group));
rd->fs->super->s_free_inodes_count += rd->fs->group_desc_count * (rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
rd->fs->super->s_inodes_per_group = rd->new_inodes_per_group;
rd->fs->super->s_inodes_count = rd->fs->group_desc_count * rd->new_inodes_per_group;
out:
if (buf)
{
@ -344,15 +347,6 @@ out:
return retval;
}
/**
* Adjust superblock and block group descriptors
*/
int change_super_and_bgd(realloc_data *rd)
{
return 0;
}
/**
* Main function: change inode number of a filesystem!
*/
@ -369,7 +363,7 @@ int do_realloc(realloc_data *rd)
(rd->new_inodes_per_group * EXT2_INODE_SIZE(rd->fs->super) +
EXT2_BLOCK_SIZE(rd->fs->super) - 1) / EXT2_BLOCK_SIZE(rd->fs->super);
rd->new_inode_count = rd->new_inodes_per_group * rd->fs->group_desc_count;
if (rd->new_inodes_per_group < rd->fs->super->s_inodes_per_group)
if (rd->new_inodes_per_group < EXT2_INODES_PER_GROUP(rd->fs->super))
{
if (rd->new_inode_count < rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count)
{
@ -377,13 +371,14 @@ int do_realloc(realloc_data *rd)
rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count);
return ENOENT;
}
printf("Phase 1: Moving inodes out of the way\n");
retval = shrink_move_inodes(rd);
if (retval)
{
return retval;
}
}
else if (rd->new_inodes_per_group > rd->fs->super->s_inodes_per_group)
else if (rd->new_inodes_per_group > EXT2_INODES_PER_GROUP(rd->fs->super))
{
blk64_t required_blocks = (rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group) * rd->fs->group_desc_count;
if (required_blocks > ext2fs_free_blocks_count(rd->fs->super))
@ -393,6 +388,7 @@ int do_realloc(realloc_data *rd)
required_blocks, ext2fs_free_blocks_count(rd->fs->super));
return ENOENT;
}
printf("Phase 1: Moving data blocks out of the way\n");
retval = extend_move_blocks(rd);
if (retval)
{
@ -404,16 +400,13 @@ int do_realloc(realloc_data *rd)
printf("The requested number of inodes is equal to current\n");
return 0;
}
printf("Phase 2: Changing all inode numbers\n");
retval = change_inode_numbers(rd);
if (retval)
{
return retval;
}
retval = flex_bg_move_itables(rd);
if (retval)
{
return retval;
}
printf("Phase 3: Adjusting superblock and block group descriptors\n");
retval = change_super_and_bgd(rd);
if (retval)
{
@ -452,13 +445,17 @@ int main(int narg, char **args)
ext2fs_struct_stat st_buf;
char *device_name, *io_options;
add_error_table(&et_ext2_error_table);
// USAGE: ./realloc-inodes <device> <new_count>
if (narg < 3)
{
printf("USAGE: ./realloc-inodes <device> <new_inode_count>\n");
return 0;
}
optind = 1;
rd.device_name = args[optind++];
rd.new_inode_count = atou(args[optind++]);
add_error_table(&et_ext2_error_table);
rd.fs_fd = ext2fs_open_file(rd.device_name, O_RDWR, 0);
if (rd.fs_fd < 0)
{
@ -481,8 +478,7 @@ int main(int narg, char **args)
{
*rd.io_options++ = 0;
}
//io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
io_flags |= EXT2_FLAG_64BITS;
io_flags = EXT2_FLAG_64BITS | EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
retval = ext2fs_open2(rd.device_name, rd.io_options, io_flags, 0, 0, unix_io_manager, &rd.fs);
if (retval)
{