Works on a VERY basic test case (shrink, no inode moving, no inode number change) with errors successfully corrected by fsck :-)))
parent
f58ece6d8c
commit
a33f91e388
130
realloc-inodes.c
130
realloc-inodes.c
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue