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
|
||||
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;
|
||||
ext2fs_mark_block_bitmap2(pb->alloc_map, block);
|
||||
ext2fs_unmark_block_bitmap2(pb->alloc_map, orig);
|
||||
ret = BLOCK_CHANGED;
|
||||
if (pb->flags & EXT2_BMOVE_DEBUG)
|
||||
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.
|
||||
*
|
||||
* 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:
|
||||
* 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
|
||||
*
|
||||
* 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>
|
||||
|
@ -42,6 +51,7 @@
|
|||
#include <ext2fs/ext2fs.h>
|
||||
|
||||
#define _(a) (a)
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
errcode_t ext2fs_move_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap reserve,
|
||||
|
@ -54,6 +64,7 @@ typedef struct
|
|||
ext2_filsys fs;
|
||||
int fs_fd;
|
||||
char *device_name, *io_options;
|
||||
__u32 old_inodes_per_group;
|
||||
__u32 new_inode_count, new_inodes_per_group, new_inode_blocks_per_group;
|
||||
// (old->new) inode number 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);
|
||||
}
|
||||
}
|
||||
// TODO Check the bad block inode
|
||||
retval = ext2fs_move_blocks(rd->fs, reserve_map, rd->fs->block_map, 2);
|
||||
retval = ext2fs_move_blocks(rd->fs, reserve_map, rd->fs->block_map, 0);
|
||||
ext2fs_mark_bb_dirty(rd->fs);
|
||||
ext2fs_flush(rd->fs);
|
||||
out:
|
||||
|
@ -396,10 +406,10 @@ int change_inode_numbers(realloc_data *rd)
|
|||
int change_super_and_bgd(realloc_data *rd)
|
||||
{
|
||||
blk64_t it_start, blk;
|
||||
dgrp_t grp, n_flex, n_grp, flex_count;
|
||||
dgrp_t grp, flex_grp, flex_count;
|
||||
__u32 unus;
|
||||
__u32 i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
||||
int flexbg_size = 0, i, retval = 0;
|
||||
int i_per_g_diff = rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super);
|
||||
int flexbg_size = 0, n_grp, i, retval = 0;
|
||||
void *buf = NULL;
|
||||
ext2fs_flush(rd->fs);
|
||||
if (!rd->fs->block_map)
|
||||
|
@ -419,20 +429,22 @@ int change_super_and_bgd(realloc_data *rd)
|
|||
{
|
||||
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;
|
||||
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
|
||||
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))
|
||||
{
|
||||
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));
|
||||
if (retval)
|
||||
{
|
||||
|
@ -441,13 +453,13 @@ int change_super_and_bgd(realloc_data *rd)
|
|||
}
|
||||
}
|
||||
// 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;
|
||||
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", 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;
|
||||
}
|
||||
// Mark/unmark extra inode table blocks
|
||||
|
@ -458,21 +470,32 @@ int change_super_and_bgd(realloc_data *rd)
|
|||
}
|
||||
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);
|
||||
}
|
||||
ext2fs_bg_free_blocks_count_set(rd->fs, n_flex*flexbg_size,
|
||||
ext2fs_bg_free_blocks_count(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, flex_grp*flexbg_size) -
|
||||
(rd->new_inode_blocks_per_group - rd->fs->inode_blocks_per_group)*flexbg_size);
|
||||
// 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;
|
||||
ext2fs_inode_table_loc_set(rd->fs, grp, blk);
|
||||
ext2fs_bg_free_inodes_count_set(rd->fs, grp,
|
||||
ext2fs_bg_free_inodes_count(rd->fs, grp) + i_per_g_diff);
|
||||
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_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
||||
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) +
|
||||
rd->new_inodes_per_group - EXT2_INODES_PER_GROUP(rd->fs->super));
|
||||
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_flags_clear(rd->fs, grp, EXT2_BG_BLOCK_UNINIT);
|
||||
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_count = rd->fs->group_desc_count * rd->new_inodes_per_group;
|
||||
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:
|
||||
if (buf)
|
||||
{
|
||||
|
@ -534,6 +582,7 @@ out:
|
|||
int do_realloc(realloc_data *rd)
|
||||
{
|
||||
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 &= ~7;
|
||||
if (rd->new_inodes_per_group < 16)
|
||||
|
|
Loading…
Reference in New Issue