Bigalloc compatibility -- OK, it works now!
parent
8ad456b992
commit
af8311fa63
20
bmove.c
20
bmove.c
|
@ -23,6 +23,7 @@ struct process_block_struct {
|
|||
char *buf;
|
||||
int add_dir;
|
||||
int flags;
|
||||
blk64_t last, last_new;
|
||||
};
|
||||
|
||||
static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
||||
|
@ -42,6 +43,16 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
|||
* Let's see if this is one which we need to relocate
|
||||
*/
|
||||
if (ext2fs_test_block_bitmap2(pb->reserve, block)) {
|
||||
if (block & EXT2FS_CLUSTER_MASK(fs)) {
|
||||
// This means we've already moved the cluster and just need
|
||||
// to rewrite numbers of a non-first block in a cluster
|
||||
if (pb->last == block-1) {
|
||||
*block_nr = pb->last_new+1;
|
||||
pb->last++;
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (blockcnt >= 0 && (pb->ino == EXT2_BAD_INO || pb->ino == EXT2_RESIZE_INO)) {
|
||||
// We obviously can't move bad blocks; and also the resize inode, because it must be in a predefined location
|
||||
// But we allow to move extent blocks (blockcnt == -1) and directory index blocks (blockcnt == -2)
|
||||
|
@ -58,17 +69,19 @@ static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
|||
} while (ext2fs_test_block_bitmap2(pb->reserve, block) ||
|
||||
ext2fs_test_block_bitmap2(pb->alloc_map, block));
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf);
|
||||
retval = io_channel_read_blk64(fs->io, orig, EXT2FS_CLUSTER_RATIO(fs), pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, pb->buf);
|
||||
retval = io_channel_write_blk64(fs->io, block, EXT2FS_CLUSTER_RATIO(fs), pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
*block_nr = block;
|
||||
pb->last = orig;
|
||||
pb->last_new = block;
|
||||
ext2fs_block_alloc_stats2(fs, orig, -1);
|
||||
ext2fs_block_alloc_stats2(fs, block, +1);
|
||||
ret = BLOCK_CHANGED;
|
||||
|
@ -109,10 +122,11 @@ errcode_t ext2fs_move_blocks(ext2_filsys fs,
|
|||
pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
|
||||
pb.flags = flags;
|
||||
|
||||
retval = ext2fs_get_array(4, fs->blocksize, &block_buf);
|
||||
retval = ext2fs_get_array(3 + EXT2FS_CLUSTER_RATIO(fs), fs->blocksize, &block_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
pb.buf = block_buf + fs->blocksize * 3;
|
||||
pb.last = -1;
|
||||
|
||||
/*
|
||||
* If GET_DBLIST is set in the flags field, then we should
|
||||
|
|
11
mkimage.sh
11
mkimage.sh
|
@ -3,12 +3,13 @@
|
|||
# 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
|
||||
FILE=test-ext4-grow.img
|
||||
FS=ext4
|
||||
FILE=${FILE:-test-ext4-grow1.img}
|
||||
FS=${FS:-ext4}
|
||||
SIZE=${SIZE:-32768}
|
||||
OPTS=${OPTS:--b 1024 -g 2048 -N 2048}
|
||||
|
||||
dd if=/dev/zero of=$FILE bs=1k seek=32767 count=1
|
||||
/sbin/mkfs.$FS -F -b 1024 -m 0 -g 2048 -N $INODES $FILE
|
||||
dd if=/dev/zero of=$FILE bs=1k seek=$((SIZE-1)) count=1
|
||||
/sbin/mkfs.$FS -F -m 0 $OPTS $FILE
|
||||
mkdir -p dir
|
||||
mount -o loop $FILE dir
|
||||
# For block moving test: create a sparse file with many extents
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
*/
|
||||
|
||||
/**
|
||||
* TODO bigalloc compatibility
|
||||
* TODO write some tests
|
||||
*
|
||||
* The theory isn't that hard:
|
||||
|
@ -71,6 +70,7 @@
|
|||
* - reallocation (both shrink and grow) in case of big flex_bg when inode
|
||||
* tables don't fit into single block group
|
||||
* - non-optimal reallocation, i.e. when inode block count doesn't change
|
||||
* - reallocation on a bigalloc filesystem
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -184,7 +184,6 @@ errcode_t 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;
|
||||
|
@ -268,10 +267,6 @@ errcode_t extend_move_blocks(realloc_data *rd)
|
|||
{
|
||||
return retval;
|
||||
}
|
||||
if (!rd->fs->block_map)
|
||||
{
|
||||
ext2fs_read_block_bitmap(rd->fs);
|
||||
}
|
||||
// Mark blocks we want to free as "reserved"
|
||||
// Don't care about which blocks are already used by inode tables,
|
||||
// because ext2fs_move_blocks only moves blocks that belong to inodes.
|
||||
|
@ -326,17 +321,14 @@ errcode_t change_inode_numbers(realloc_data *rd)
|
|||
*/
|
||||
errcode_t change_super_and_bgd(realloc_data *rd)
|
||||
{
|
||||
blk64_t blk;
|
||||
blk64_t blk, end;
|
||||
dgrp_t grp, n_grp, flex_grp;
|
||||
__u32 used_ig, used_ibg, i, unus;
|
||||
errcode_t retval = 0;
|
||||
int has_gdt_csum = EXT2_HAS_RO_COMPAT_FEATURE(rd->fs->super, EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
|
||||
int cl = EXT2FS_CLUSTER_RATIO(rd->fs);
|
||||
void *buf = NULL;
|
||||
ext2fs_flush(rd->fs);
|
||||
if (!rd->fs->block_map)
|
||||
{
|
||||
ext2fs_read_block_bitmap(rd->fs);
|
||||
}
|
||||
retval = ext2fs_get_mem(EXT2_BLOCK_SIZE(rd->fs->super) * rd->ibg_new * rd->flexbg_size, &buf);
|
||||
if (retval)
|
||||
{
|
||||
|
@ -345,14 +337,28 @@ errcode_t change_super_and_bgd(realloc_data *rd)
|
|||
// First mark/unmark inode table blocks (mark and unmark in separate passes)
|
||||
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
||||
{
|
||||
for (i = 0, blk = ext2fs_inode_table_loc(rd->fs, grp); i < rd->ibg_old; i++, blk++)
|
||||
// In case of bigalloc, last cluster of previous group inode table
|
||||
// may often overlap with the first cluster of next group one
|
||||
blk = ext2fs_inode_table_loc(rd->fs, grp) & ~(cl-1);
|
||||
if (!ext2fs_test_block_bitmap2(rd->fs->block_map, blk))
|
||||
{
|
||||
blk += cl;
|
||||
}
|
||||
end = (ext2fs_inode_table_loc(rd->fs, grp) + rd->ibg_old + (cl-1)) & ~(cl-1);
|
||||
for (; blk < end; blk += cl)
|
||||
{
|
||||
ext2fs_block_alloc_stats2(rd->fs, blk, -1);
|
||||
}
|
||||
}
|
||||
for (grp = 0; grp < rd->fs->group_desc_count; grp++)
|
||||
{
|
||||
for (i = 0, blk = rd->new_itable_loc[grp]; i < rd->ibg_new; i++, blk++)
|
||||
blk = rd->new_itable_loc[grp] & ~(cl-1);
|
||||
if (grp > 0 && blk == end-cl)
|
||||
{
|
||||
blk += cl;
|
||||
}
|
||||
end = (rd->new_itable_loc[grp] + rd->ibg_new + (cl-1)) & ~(cl-1);
|
||||
for (; blk < end; blk += cl)
|
||||
{
|
||||
if (ext2fs_test_block_bitmap2(rd->fs->block_map, blk))
|
||||
{
|
||||
|
@ -427,7 +433,6 @@ errcode_t change_super_and_bgd(realloc_data *rd)
|
|||
unus = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -488,8 +493,8 @@ errcode_t alloc_itables(realloc_data *rd)
|
|||
errcode_t retval = 0;
|
||||
ext2fs_block_bitmap nonmovable = NULL;
|
||||
dgrp_t grp, flex_grp;
|
||||
int n_grp, i;
|
||||
blk64_t blk, end;
|
||||
int n_grp, i, mod;
|
||||
blk64_t blk, start, end;
|
||||
retval = ext2fs_get_mem(sizeof(blk64_t) * rd->fs->group_desc_count, &rd->new_itable_loc);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
@ -528,15 +533,23 @@ errcode_t alloc_itables(realloc_data *rd)
|
|||
// TODO We could use a better algorithm that would always try to find
|
||||
// the biggest free sequence of blocks if it can't allocate all inode
|
||||
// tables in sequence
|
||||
blk = ext2fs_group_first_block2(rd->fs, grp);
|
||||
start = ext2fs_group_first_block2(rd->fs, grp);
|
||||
end = ext2fs_group_last_block2(rd->fs, grp+n_grp-1);
|
||||
mod = 0;
|
||||
for (i = 0; i < n_grp; i++, grp++)
|
||||
{
|
||||
retval = ext2fs_get_free_blocks2(rd->fs, blk, end, rd->ibg_new, nonmovable, &blk);
|
||||
retval = ext2fs_get_free_blocks2(rd->fs, start, end, rd->ibg_new, nonmovable, &blk);
|
||||
if (retval)
|
||||
goto out;
|
||||
if (start == blk)
|
||||
blk += mod;
|
||||
rd->new_itable_loc[grp] = blk;
|
||||
blk += rd->ibg_new;
|
||||
start = blk + rd->ibg_new;
|
||||
// Allow adjacent inode tables to share one cluster
|
||||
// ext2fs_get_free_blocks2 operates on cluster boundaries,
|
||||
// so we handle the division residue separately
|
||||
mod = start & EXT2FS_CLUSTER_MASK(rd->fs);
|
||||
start = start - mod;
|
||||
}
|
||||
}
|
||||
out:
|
||||
|
@ -579,6 +592,7 @@ errcode_t do_realloc(realloc_data *rd)
|
|||
" - there will be wasted space in inode tables. Optimal inode count would be %u.\n",
|
||||
rd->new_inode_count, rd->ig_new, EXT2_BLOCK_SIZE(rd->fs->super) / EXT2_INODE_SIZE(rd->fs->super), ig_round);
|
||||
}
|
||||
ext2fs_read_bitmaps(rd->fs);
|
||||
// Find where to put the new inode tables
|
||||
retval = alloc_itables(rd);
|
||||
if (retval)
|
||||
|
|
Loading…
Reference in New Issue