Inode table growing now works on a basic test case!
parent
9f543c9ca1
commit
36ac4a8330
2
Makefile
2
Makefile
|
@ -1,3 +1,3 @@
|
||||||
all: realloc-inodes
|
all: realloc-inodes
|
||||||
realloc-inodes: realloc-inodes.c bmove.c ext2fsP.h
|
realloc-inodes: realloc-inodes.c bmove.c ext2fsP.h
|
||||||
gcc -Wall -o realloc-inodes -lcom_err -lext2fs realloc-inodes.c bmove.c
|
gcc -Wsign-compare -Wall -o realloc-inodes -lcom_err -lext2fs realloc-inodes.c bmove.c
|
||||||
|
|
1
bmove.c
1
bmove.c
|
@ -75,6 +75,7 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
||||||
}
|
}
|
||||||
*block_nr = block;
|
*block_nr = block;
|
||||||
ext2fs_mark_block_bitmap2(pb->alloc_map, block);
|
ext2fs_mark_block_bitmap2(pb->alloc_map, block);
|
||||||
|
ext2fs_unmark_block_bitmap2(pb->alloc_map, orig);
|
||||||
ret = BLOCK_CHANGED;
|
ret = BLOCK_CHANGED;
|
||||||
if (pb->flags & EXT2_BMOVE_DEBUG)
|
if (pb->flags & EXT2_BMOVE_DEBUG)
|
||||||
printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
|
printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# To test shrinking: INODES=8192, then ./realloc-inodes test-clean.img 2048
|
||||||
|
# To test growing: INODES=2048, then ./realloc-inodes test-clean.img 8192
|
||||||
|
|
||||||
|
INODES=2048
|
||||||
|
|
||||||
|
dd if=/dev/zero of=test-clean.img bs=1k seek=32767 count=1
|
||||||
|
/sbin/mkfs.ext4 -F -b 1024 -m 0 -g 2048 -N $INODES test-clean.img
|
||||||
|
mkdir -p dir
|
||||||
|
mount -o loop test-clean.img dir
|
||||||
|
# For block moving test: create a sparse file with many extents
|
||||||
|
dd if=/dev/urandom of=dir/f_random bs=1k count=1
|
||||||
|
for i in {1..1200}; do
|
||||||
|
dd if=dir/f_random of=dir/f_sparse bs=1k count=1 seek=$((2400-i*2)) conv=notrunc 2>/dev/null
|
||||||
|
done
|
||||||
|
# For inode moving test: create 1201 1kb sized files
|
||||||
|
dd if=/dev/zero of=dir/f_zero bs=1k count=1
|
||||||
|
for i in {1..1200}; do
|
||||||
|
cp dir/f_zero dir/f$i
|
||||||
|
done
|
||||||
|
umount dir
|
|
@ -3,6 +3,13 @@
|
||||||
* without recreating it.
|
* without recreating it.
|
||||||
*
|
*
|
||||||
* TODO bigalloc compatibility
|
* TODO bigalloc compatibility
|
||||||
|
* TODO support undo, but not by undo_io_manager because it is VERY slow
|
||||||
|
* TODO check the bad block inode before block moving
|
||||||
|
* TODO check if the block mover does block_alloc_stats
|
||||||
|
* TODO try to remove duplicate code constructs
|
||||||
|
* TODO write some tests: for inode moving (image with many files),
|
||||||
|
* for block moving, including extent blocks (one sparse file with many extents),
|
||||||
|
* for calculating block group statistics (block moving between different groups)
|
||||||
*
|
*
|
||||||
* The theory isn't that hard:
|
* The theory isn't that hard:
|
||||||
* 1) If shrinking - move inodes away from the end of each block group inode table
|
* 1) If shrinking - move inodes away from the end of each block group inode table
|
||||||
|
@ -25,7 +32,9 @@
|
||||||
* s_free_inodes_count, s_inodes_per_group
|
* s_free_inodes_count, s_inodes_per_group
|
||||||
*
|
*
|
||||||
* This is a highly destructive process and WILL leave a corrupted FS if interrupted.
|
* This is a highly destructive process and WILL leave a corrupted FS if interrupted.
|
||||||
* So we should provide a rollback method... maybe use undo_io_manager?
|
* So we should provide a rollback method. undo_io_manager is very slow, so maybe the
|
||||||
|
* original idea should be implemented: create the "patch" i/o manager that writes all
|
||||||
|
* changed blocks to a separate file and only then applies it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -42,6 +51,7 @@
|
||||||
#include <ext2fs/ext2fs.h>
|
#include <ext2fs/ext2fs.h>
|
||||||
|
|
||||||
#define _(a) (a)
|
#define _(a) (a)
|
||||||
|
#define min(a,b) ((a)<(b)?(a):(b))
|
||||||
|
|
||||||
errcode_t ext2fs_move_blocks(ext2_filsys fs,
|
errcode_t ext2fs_move_blocks(ext2_filsys fs,
|
||||||
ext2fs_block_bitmap reserve,
|
ext2fs_block_bitmap reserve,
|
||||||
|
@ -54,6 +64,7 @@ typedef struct
|
||||||
ext2_filsys fs;
|
ext2_filsys fs;
|
||||||
int fs_fd;
|
int fs_fd;
|
||||||
char *device_name, *io_options;
|
char *device_name, *io_options;
|
||||||
|
__u32 old_inodes_per_group;
|
||||||
__u32 new_inode_count, new_inodes_per_group, new_inode_blocks_per_group;
|
__u32 new_inode_count, new_inodes_per_group, new_inode_blocks_per_group;
|
||||||
// (old->new) inode number map
|
// (old->new) inode number map
|
||||||
ext2_ino_t *inode_map;
|
ext2_ino_t *inode_map;
|
||||||
|
@ -345,8 +356,7 @@ int extend_move_blocks(realloc_data *rd)
|
||||||
ext2fs_mark_block_bitmap_range2(reserve_map, it_start, rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
|
ext2fs_mark_block_bitmap_range2(reserve_map, it_start, rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO Check the bad block inode
|
retval = ext2fs_move_blocks(rd->fs, reserve_map, rd->fs->block_map, 0);
|
||||||
retval = ext2fs_move_blocks(rd->fs, reserve_map, rd->fs->block_map, 2);
|
|
||||||
ext2fs_mark_bb_dirty(rd->fs);
|
ext2fs_mark_bb_dirty(rd->fs);
|
||||||
ext2fs_flush(rd->fs);
|
ext2fs_flush(rd->fs);
|
||||||
out:
|
out:
|
||||||
|
@ -396,10 +406,10 @@ int change_inode_numbers(realloc_data *rd)
|
||||||
int change_super_and_bgd(realloc_data *rd)
|
int change_super_and_bgd(realloc_data *rd)
|
||||||
{
|
{
|
||||||
blk64_t it_start, blk;
|
blk64_t it_start, blk;
|
||||||
dgrp_t grp, n_flex, n_grp, flex_count;
|
dgrp_t grp, flex_grp, flex_count;
|
||||||
__u32 unus;
|
__u32 unus;
|
||||||
__u32 i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
int i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
||||||
int flexbg_size = 0, i, retval = 0;
|
int flexbg_size = 0, n_grp, i, retval = 0;
|
||||||
void *buf = NULL;
|
void *buf = NULL;
|
||||||
ext2fs_flush(rd->fs);
|
ext2fs_flush(rd->fs);
|
||||||
if (!rd->fs->block_map)
|
if (!rd->fs->block_map)
|
||||||
|
@ -419,20 +429,22 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
{
|
{
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
for (n_flex = 0; n_flex < flex_count; n_flex++)
|
for (flex_grp = 0; flex_grp < flex_count; flex_grp++)
|
||||||
{
|
{
|
||||||
|
memset(buf, 0, EXT2_BLOCK_SIZE(rd->fs->super) * rd->new_inode_blocks_per_group * flexbg_size);
|
||||||
n_grp = flexbg_size;
|
n_grp = flexbg_size;
|
||||||
if (n_flex*flexbg_size+n_grp > rd->fs->group_desc_count)
|
if (flex_grp*flexbg_size+n_grp > rd->fs->group_desc_count)
|
||||||
{
|
{
|
||||||
n_grp = rd->fs->group_desc_count-n_flex*flexbg_size;
|
n_grp = rd->fs->group_desc_count-flex_grp*flexbg_size;
|
||||||
}
|
}
|
||||||
// Read inode tables
|
// Read inode tables
|
||||||
for (grp = n_flex*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
||||||
{
|
{
|
||||||
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
|
if (!ext2fs_bg_flags_test(rd->fs, grp, EXT2_BG_INODE_UNINIT))
|
||||||
{
|
{
|
||||||
blk = ext2fs_inode_table_loc(rd->fs, grp);
|
blk = ext2fs_inode_table_loc(rd->fs, grp);
|
||||||
retval = io_channel_read_blk64(rd->fs->io, blk, rd->new_inode_blocks_per_group,
|
retval = io_channel_read_blk64(rd->fs->io, blk,
|
||||||
|
min(rd->fs->inode_blocks_per_group, rd->new_inode_blocks_per_group),
|
||||||
buf + i*rd->new_inode_blocks_per_group*EXT2_BLOCK_SIZE(rd->fs->super));
|
buf + i*rd->new_inode_blocks_per_group*EXT2_BLOCK_SIZE(rd->fs->super));
|
||||||
if (retval)
|
if (retval)
|
||||||
{
|
{
|
||||||
|
@ -441,13 +453,13 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Write inode table to the new place
|
// Write inode table to the new place
|
||||||
it_start = ext2fs_inode_table_loc(rd->fs, n_flex*flexbg_size);
|
it_start = ext2fs_inode_table_loc(rd->fs, flex_grp*flexbg_size);
|
||||||
blk = rd->new_inode_blocks_per_group * n_grp;
|
blk = rd->new_inode_blocks_per_group * n_grp;
|
||||||
retval = io_channel_write_blk64(rd->fs->io, it_start, blk, buf);
|
retval = io_channel_write_blk64(rd->fs->io, it_start, blk, buf);
|
||||||
if (retval)
|
if (retval)
|
||||||
{
|
{
|
||||||
// The FS is badly corrupted now :-(
|
// The FS is badly corrupted now :-(
|
||||||
printf("Error moving inode tables for %u groups, starting from %u\n", n_grp, n_flex*flexbg_size);
|
printf("Error moving inode tables for %u groups, starting from %u\n", n_grp, flex_grp*flexbg_size);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
// Mark/unmark extra inode table blocks
|
// Mark/unmark extra inode table blocks
|
||||||
|
@ -458,21 +470,32 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start+blk,
|
ext2fs_mark_block_bitmap_range2(rd->fs->block_map, it_start+rd->fs->inode_blocks_per_group*n_grp,
|
||||||
(rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*n_grp);
|
(rd->new_inode_blocks_per_group-rd->fs->inode_blocks_per_group)*n_grp);
|
||||||
}
|
}
|
||||||
ext2fs_bg_free_blocks_count_set(rd->fs, n_flex*flexbg_size,
|
ext2fs_bg_free_blocks_count_set(rd->fs, flex_grp*flexbg_size,
|
||||||
ext2fs_bg_free_blocks_count(rd->fs, n_flex*flexbg_size) -
|
ext2fs_bg_free_blocks_count(rd->fs, flex_grp*flexbg_size) -
|
||||||
(rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group)*flexbg_size);
|
(rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group)*flexbg_size);
|
||||||
// Change inode table locations and free inode counts
|
// Change inode table locations and free inode counts
|
||||||
for (grp = n_flex*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
for (grp = flex_grp*flexbg_size, i = 0; i < n_grp; grp++, i++)
|
||||||
{
|
{
|
||||||
blk = it_start + rd->new_inode_blocks_per_group*i;
|
blk = it_start + rd->new_inode_blocks_per_group*i;
|
||||||
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
|
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
|
||||||
ext2fs_bg_free_inodes_count_set(rd->fs, grp,
|
ext2fs_bg_free_inodes_count_set(rd->fs, grp,
|
||||||
ext2fs_bg_free_inodes_count(rd->fs, grp) + i_per_g_diff);
|
ext2fs_bg_free_inodes_count(rd->fs, grp) + i_per_g_diff);
|
||||||
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
||||||
unus = unus < i_per_g_diff ? 0 : unus - i_per_g_diff;
|
if (i_per_g_diff > 0)
|
||||||
|
{
|
||||||
|
unus += i_per_g_diff;
|
||||||
|
}
|
||||||
|
else if (unus < (unsigned)-i_per_g_diff)
|
||||||
|
{
|
||||||
|
unus = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unus = unus + i_per_g_diff;
|
||||||
|
}
|
||||||
ext2fs_bg_itable_unused_set(rd->fs, grp, unus);
|
ext2fs_bg_itable_unused_set(rd->fs, grp, unus);
|
||||||
ext2fs_bg_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
ext2fs_bg_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
||||||
ext2fs_group_desc_csum_set(rd->fs, grp);
|
ext2fs_group_desc_csum_set(rd->fs, grp);
|
||||||
|
@ -500,7 +523,18 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
ext2fs_bg_free_inodes_count_set(rd->fs, grp, ext2fs_bg_free_inodes_count(rd->fs, grp) +
|
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));
|
rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
|
||||||
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
unus = ext2fs_bg_itable_unused(rd->fs, grp);
|
||||||
unus = unus < i_per_g_diff ? 0 : unus - i_per_g_diff;
|
if (i_per_g_diff > 0)
|
||||||
|
{
|
||||||
|
unus += i_per_g_diff;
|
||||||
|
}
|
||||||
|
else if (unus < (unsigned)-i_per_g_diff)
|
||||||
|
{
|
||||||
|
unus = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unus = unus + i_per_g_diff;
|
||||||
|
}
|
||||||
ext2fs_bg_itable_unused_set(rd->fs, grp, unus);
|
ext2fs_bg_itable_unused_set(rd->fs, grp, unus);
|
||||||
ext2fs_bg_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
ext2fs_bg_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
||||||
ext2fs_group_desc_csum_set(rd->fs, grp);
|
ext2fs_group_desc_csum_set(rd->fs, grp);
|
||||||
|
@ -520,6 +554,20 @@ int change_super_and_bgd(realloc_data *rd)
|
||||||
rd->fs->super->s_inodes_per_group = rd->new_inodes_per_group;
|
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;
|
rd->fs->super->s_inodes_count = rd->fs->group_desc_count * rd->new_inodes_per_group;
|
||||||
ext2fs_mark_super_dirty(rd->fs);
|
ext2fs_mark_super_dirty(rd->fs);
|
||||||
|
if (rd->new_inodes_per_group > rd->old_inodes_per_group)
|
||||||
|
{
|
||||||
|
// Mark newly allocated inodes as free
|
||||||
|
__u32 ino;
|
||||||
|
ext2fs_read_inode_bitmap(rd->fs);
|
||||||
|
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
||||||
|
{
|
||||||
|
for (ino = rd->old_inodes_per_group; ino < rd->new_inodes_per_group; ino++)
|
||||||
|
{
|
||||||
|
ext2fs_unmark_inode_bitmap2(rd->fs->inode_map, 1 + ino + grp*rd->new_inodes_per_group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ext2fs_mark_ib_dirty(rd->fs);
|
||||||
|
}
|
||||||
out:
|
out:
|
||||||
if (buf)
|
if (buf)
|
||||||
{
|
{
|
||||||
|
@ -534,6 +582,7 @@ out:
|
||||||
int do_realloc(realloc_data *rd)
|
int do_realloc(realloc_data *rd)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
|
rd->old_inodes_per_group = EXT2_INODES_PER_GROUP(rd->fs->super);
|
||||||
rd->new_inodes_per_group = rd->new_inode_count / rd->fs->group_desc_count;
|
rd->new_inodes_per_group = rd->new_inode_count / rd->fs->group_desc_count;
|
||||||
rd->new_inodes_per_group &= ~7;
|
rd->new_inodes_per_group &= ~7;
|
||||||
if (rd->new_inodes_per_group < 16)
|
if (rd->new_inodes_per_group < 16)
|
||||||
|
|
Loading…
Reference in New Issue