Roughly implemented inode table moving
parent
bf357faaf4
commit
f58ece6d8c
178
realloc-inodes.c
178
realloc-inodes.c
|
@ -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 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 group, i, last = rd->inode_map_size;
|
||||||
__u32 new_group;
|
__u32 new_group;
|
||||||
ext2_ino_t ino, new_ino;
|
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 (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 < rd->fs->super->s_inodes_per_group; i++)
|
||||||
|
@ -143,32 +149,49 @@ int shrink_move_inodes(realloc_data *rd)
|
||||||
} while (new_group != group);
|
} while (new_group != group);
|
||||||
if (retval)
|
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);
|
realloc_add_inode_map(rd, ino, new_ino);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Move inodes
|
out:
|
||||||
for (i = last; i < rd->inode_map_size; i++)
|
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
|
* so the tables can be grown
|
||||||
*/
|
*/
|
||||||
int extend_move_blocks(realloc_data *rd)
|
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,
|
struct ext2_dir_entry *dirent, int offset,
|
||||||
int blocksize, char *buf, void *priv_data)
|
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);
|
strncpy(name, dirent->name, dirent->name_len & 0xff);
|
||||||
name[dirent->name_len & 0xff] = 0;
|
name[dirent->name_len & 0xff] = 0;
|
||||||
printf("%s: old %d, new %d\n", name, dirent->inode, new_ino);
|
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;
|
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 change_inode_numbers(realloc_data *rd)
|
||||||
{
|
{
|
||||||
int i, j, retval;
|
int j, retval;
|
||||||
|
dgrp_t grp;
|
||||||
blk64_t blk;
|
blk64_t blk;
|
||||||
void *buf;
|
void *buf;
|
||||||
struct ext2_inode *inode;
|
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);
|
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
|
// read inode table of a group
|
||||||
blk = ext2fs_inode_table_loc(rd->fs, i);
|
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
|
||||||
retval = io_channel_read_blk64(rd->fs->io, blk, rd->fs->inode_blocks_per_group, buf);
|
|
||||||
if (retval)
|
|
||||||
{
|
{
|
||||||
break;
|
blk = ext2fs_inode_table_loc(rd->fs, grp);
|
||||||
}
|
retval = io_channel_read_blk64(rd->fs->io, blk, rd->fs->inode_blocks_per_group, buf);
|
||||||
for (j = 0; j < rd->fs->super->s_inodes_per_group; j++)
|
if (retval)
|
||||||
{
|
|
||||||
inode = (struct ext2_inode*)(buf + EXT2_INODE_SIZE(rd->fs->super) * j);
|
|
||||||
if (inode->i_mode & S_IFDIR)
|
|
||||||
{
|
{
|
||||||
printf("Directory %d\n", 1+j+i*rd->fs->super->s_inodes_per_group);
|
break;
|
||||||
ext2fs_dir_iterate2(rd->fs, 1+j+i*rd->fs->super->s_inodes_per_group, 0, 0, change_inode_numbers_callback, rd);
|
}
|
||||||
printf("\n");
|
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
|
* 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)
|
int change_super_and_bgd(realloc_data *rd)
|
||||||
{
|
{
|
||||||
|
@ -288,6 +409,11 @@ int do_realloc(realloc_data *rd)
|
||||||
{
|
{
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
retval = flex_bg_move_itables(rd);
|
||||||
|
if (retval)
|
||||||
|
{
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
retval = change_super_and_bgd(rd);
|
retval = change_super_and_bgd(rd);
|
||||||
if (retval)
|
if (retval)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue