Roughly implemented inode table moving

master
Vitaliy Filippov 2013-12-27 17:13:24 +00:00
parent bf357faaf4
commit f58ece6d8c
1 changed files with 152 additions and 26 deletions

View File

@ -117,10 +117,16 @@ ext2_ino_t realloc_search_inode_map(realloc_data *rd, ext2_ino_t old)
*/
int shrink_move_inodes(realloc_data *rd)
{
int retval;
int retval = 0, inode_size = EXT2_INODE_SIZE(rd->fs->super);
__u32 group, i, last = rd->inode_map_size;
__u32 new_group;
ext2_ino_t ino, new_ino;
struct ext2_inode *inode = NULL;
retval = ext2fs_get_mem(inode_size, &inode);
if (retval)
{
return retval;
}
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++)
@ -143,32 +149,49 @@ int shrink_move_inodes(realloc_data *rd)
} while (new_group != group);
if (retval)
{
return ENOENT;
// No space to move this inode
goto out;
}
// Copy inode to the new place
retval = ext2fs_read_inode_full(rd->fs, ino, inode, inode_size);
if (retval)
{
goto out;
}
retval = ext2fs_write_inode_full(rd->fs, new_ino, inode, inode_size);
if (retval)
{
goto out;
}
retval = ext2fs_mark_inode_bitmap2(rd->fs->inode_map, new_ino);
if (retval)
{
goto out;
}
// Remember mapping
realloc_add_inode_map(rd, ino, new_ino);
}
}
}
// Move inodes
for (i = last; i < rd->inode_map_size; i++)
out:
if (inode)
{
ino = rd->inode_map[i<<1];
ext2fs_free_mem(&inode);
}
return 0;
return retval;
}
/**
* Move blocks from after the end of each block group inode table
* Move data blocks from after the end of each block group inode table
* so the tables can be grown
*/
int extend_move_blocks(realloc_data *rd)
{
return 0;
return ENOSYS;
}
int change_inode_numbers_callback(ext2_ino_t dir, int entry,
static int change_inode_numbers_callback(ext2_ino_t dir, int entry,
struct ext2_dir_entry *dirent, int offset,
int blocksize, char *buf, void *priv_data)
{
@ -184,6 +207,11 @@ int change_inode_numbers_callback(ext2_ino_t dir, int entry,
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);
if (new_ino != dirent->inode)
{
dirent->inode = new_ino;
return DIRENT_CHANGED;
}
return 0;
}
@ -192,29 +220,33 @@ int change_inode_numbers_callback(ext2_ino_t dir, int entry,
*/
int change_inode_numbers(realloc_data *rd)
{
int i, j, retval;
int j, retval;
dgrp_t grp;
blk64_t blk;
void *buf;
struct ext2_inode *inode;
retval = ext2fs_get_mem(rd->fs->blocksize * rd->fs->inode_blocks_per_group, &buf);
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->fs->inode_blocks_per_group, &buf);
realloc_sort_inode_map(rd);
for (i = 0; i < rd->fs->group_desc_count; i++)
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
{
// read inode table of a group
blk = ext2fs_inode_table_loc(rd->fs, i);
retval = io_channel_read_blk64(rd->fs->io, blk, rd->fs->inode_blocks_per_group, buf);
if (retval)
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
{
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)
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)
{
printf("Directory %d\n", 1+j+i*rd->fs->super->s_inodes_per_group);
ext2fs_dir_iterate2(rd->fs, 1+j+i*rd->fs->super->s_inodes_per_group, 0, 0, change_inode_numbers_callback, rd);
printf("\n");
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");
}
}
}
}
@ -224,7 +256,96 @@ int change_inode_numbers(realloc_data *rd)
/**
* If flex_bg is enabled, move inode tables so they are consecutive again
* Then adjust superblock and block group descriptors
*/
int flex_bg_move_itables(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);
if (rd->new_inode_blocks_per_group != rd->fs->inode_blocks_per_group)
{
// 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)
{
flexbg_size = 1 << rd->fs->super->s_log_groups_per_flex;
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size, &buf);
if (retval)
{
goto out;
}
for (n_flex = 0; n_flex < rd->fs->group_desc_count/flexbg_size; n_flex++)
{
last_grp = (n_flex+1)*flexbg_size;
if (last_grp > rd->fs->group_desc_count)
{
last_grp = rd->fs->group_desc_count;
}
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 = ext2fs_inode_table_loc(rd->fs, grp);
retval = io_channel_read_blk64(rd->fs->io, blk, rd->new_inode_blocks_per_group,
buf + i*rd->new_inode_blocks_per_group*EXT2_BLOCK_SIZE(rd->fs->super));
if (retval)
{
goto out;
}
}
}
it_start = ext2fs_inode_table_loc(rd->fs, n_flex*flexbg_size);
blk = rd->new_inode_blocks_per_group * (last_grp-n_flex*flexbg_size);
retval = io_channel_write_blk64(rd->fs->io, it_start, blk, buf);
if (retval)
{
// The FS is badly corrupted now :-(
printf("Error moving inode tables for %u groups, starting from %u\n", last_grp-n_flex*flexbg_size, n_flex*flexbg_size);
goto out;
}
// 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);
}
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);
}
}
}
else
{
// Mark/unmark extra inode table blocks (without flex_bg)
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
{
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
{
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);
}
else
{
ext2fs_mark_block_bitmap_range(rd->fs->block_map, it_start, rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
}
}
}
}
}
out:
if (buf)
{
ext2fs_free_mem(&buf);
}
return retval;
}
/**
* Adjust superblock and block group descriptors
*/
int change_super_and_bgd(realloc_data *rd)
{
@ -288,6 +409,11 @@ int do_realloc(realloc_data *rd)
{
return retval;
}
retval = flex_bg_move_itables(rd);
if (retval)
{
return retval;
}
retval = change_super_and_bgd(rd);
if (retval)
{