Make a local data struct, add some routines

master
Vitaliy Filippov 2013-12-27 12:47:10 +00:00
parent 6cb0239e7e
commit bf357faaf4
1 changed files with 230 additions and 59 deletions

View File

@ -40,12 +40,20 @@
#define _(a) (a)
// "local data" for the inode reallocation process
typedef struct
{
__u32 *inode_map, inode_map_size, inode_map_alloc;
ext2_filsys fs;
int fs_fd;
char *device_name, *io_options;
__u32 new_inode_count, new_inodes_per_group, new_inode_blocks_per_group;
// (old->new) inode number map
ext2_ino_t *inode_map;
__u32 inode_map_size, inode_map_alloc;
} realloc_data;
void add_inode_map(realloc_data *rd, __u32 old, __u32 new)
// Utility functions for (old -> new) inode number map
void realloc_add_inode_map(realloc_data *rd, ext2_ino_t old, ext2_ino_t new)
{
if (!old || !new)
{
@ -54,30 +62,31 @@ void add_inode_map(realloc_data *rd, __u32 old, __u32 new)
if (2*rd->inode_map_size >= rd->inode_map_alloc)
{
rd->inode_map_alloc += 1024;
rd->inode_map = realloc(rd->inode_map, sizeof(__u32) * rd->inode_map_alloc);
rd->inode_map = realloc(rd->inode_map, sizeof(ext2_ino_t) * rd->inode_map_alloc);
}
rd->inode_map[rd->inode_map_size*2] = old;
rd->inode_map[rd->inode_map_size*2+1] = new;
rd->inode_map_size++;
}
int compare_inode_map(const void *a, const void *b)
int realloc_compare_inode_map_callback(const void *a, const void *b)
{
return *((__u32*)a) - *((__u32*)b);
return *((ext2_ino_t*)a) - *((ext2_ino_t*)b);
}
void sort_inode_map(realloc_data *rd)
void realloc_sort_inode_map(realloc_data *rd)
{
if (!rd->inode_map)
{
return;
}
qsort(rd->inode_map, rd->inode_map_size, sizeof(__u32)*2, compare_inode_map);
qsort(rd->inode_map, rd->inode_map_size, sizeof(ext2_ino_t)*2, realloc_compare_inode_map_callback);
}
__u32 search_inode_map(realloc_data *rd, __u32 old)
ext2_ino_t realloc_search_inode_map(realloc_data *rd, ext2_ino_t old)
{
__u32 start = 0, end = rd->inode_map_size, cur, cur_old;
__u32 start = 0, end = rd->inode_map_size, cur;
ext2_ino_t cur_ino;
if (!rd->inode_map)
{
return 0;
@ -85,12 +94,12 @@ __u32 search_inode_map(realloc_data *rd, __u32 old)
while (end-start > 1)
{
cur = (start+end)>>1;
cur_old = rd->inode_map[cur<<1];
if (cur < old)
cur_ino = rd->inode_map[cur<<1];
if (cur_ino < old)
{
start = cur+1;
}
else if (cur > old)
else if (cur_ino > old)
{
end = cur;
}
@ -102,106 +111,268 @@ __u32 search_inode_map(realloc_data *rd, __u32 old)
return 0;
}
const char *program_name = "realloc-inodes";
int change_inode_numbers(ext2_ino_t dir, int entry,
struct ext2_dir_entry *dirent, int offset,
int blocksize, char *buf, void *priv_data)
/**
* Move inodes from the end of each block group inode table
* so the tables can be shrinked
*/
int shrink_move_inodes(realloc_data *rd)
{
unsigned int *i_per_g = priv_data;
char name[EXT2_NAME_LEN+1];
strncpy(name, dirent->name, dirent->name_len & 0xff);
name[dirent->name_len & 0xff] = 0;
printf("%s: old %d, new %d\n", name, dirent->inode, 1 + (dirent->inode-1)/i_per_g[0]*i_per_g[1] + (dirent->inode-1)%i_per_g[0]);
int retval;
__u32 group, i, last = rd->inode_map_size;
__u32 new_group;
ext2_ino_t ino, new_ino;
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++)
{
ino = 1 + group*rd->fs->super->s_inodes_per_group + i;
if (ext2fs_test_inode_bitmap(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);
if (!retval)
{
break;
}
new_group = (new_group+1) % rd->fs->group_desc_count;
} while (new_group != group);
if (retval)
{
return ENOENT;
}
realloc_add_inode_map(rd, ino, new_ino);
}
}
}
// Move inodes
for (i = last; i < rd->inode_map_size; i++)
{
ino = rd->inode_map[i<<1];
}
return 0;
}
// try to read out all directory inodes?
void test(ext2_filsys fs)
/**
* Move blocks from after the end of each block group inode table
* so the tables can be grown
*/
int extend_move_blocks(realloc_data *rd)
{
return 0;
}
int change_inode_numbers_callback(ext2_ino_t dir, int entry,
struct ext2_dir_entry *dirent, int offset,
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);
return 0;
}
/**
* Change inode numbers in all directory entries
*/
int change_inode_numbers(realloc_data *rd)
{
int i, j, retval;
blk64_t blk;
void *buf;
struct ext2_inode *inode;
unsigned int old_new_i_per_g[2];
old_new_i_per_g[0] = fs->super->s_inodes_per_group;
old_new_i_per_g[1] = fs->super->s_inodes_per_group/2;
retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group, &buf);
for (i = 0; i < fs->group_desc_count; i++)
retval = ext2fs_get_mem(rd->fs->blocksize * rd->fs->inode_blocks_per_group, &buf);
realloc_sort_inode_map(rd);
for (i = 0; i < rd->fs->group_desc_count; i++)
{
// read inode table of a group
blk = ext2fs_inode_table_loc(fs, i);
retval = io_channel_read_blk64(fs->io, blk, fs->inode_blocks_per_group, buf);
blk = ext2fs_inode_table_loc(rd->fs, i);
retval = io_channel_read_blk64(rd->fs->io, blk, rd->fs->inode_blocks_per_group, buf);
if (retval)
{
goto errout;
break;
}
for (j = 0; j < fs->super->s_inodes_per_group; j++)
for (j = 0; j < rd->fs->super->s_inodes_per_group; j++)
{
inode = (struct ext2_inode*)(buf + EXT2_INODE_SIZE(fs->super) * 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+i*fs->super->s_inodes_per_group);
ext2fs_dir_iterate2(fs, 1+j+i*fs->super->s_inodes_per_group, 0, 0, change_inode_numbers, old_new_i_per_g);
printf("Directory %d\n", 1+j+i*rd->fs->super->s_inodes_per_group);
ext2fs_dir_iterate2(rd->fs, 1+j+i*rd->fs->super->s_inodes_per_group, 0, 0, change_inode_numbers_callback, rd);
printf("\n");
}
}
}
errout:
ext2fs_free_mem(&buf);
return 0;
}
/**
* If flex_bg is enabled, move inode tables so they are consecutive again
* Then adjust superblock and block group descriptors
*/
int change_super_and_bgd(realloc_data *rd)
{
return 0;
}
/**
* Main function: change inode number of a filesystem!
*/
int do_realloc(realloc_data *rd)
{
int retval;
rd->new_inodes_per_group = rd->new_inode_count / rd->fs->group_desc_count;
if (rd->new_inodes_per_group < 16)
{
printf("Too small number of inodes requested, min inodes per group = 16\n");
return ENOENT;
}
rd->new_inode_blocks_per_group =
(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_inode_count < rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count)
{
printf("Too small number of inodes requested, existing inodes (%u) won't fit\n",
rd->fs->super->s_inodes_count - rd->fs->super->s_free_inodes_count);
return ENOENT;
}
retval = shrink_move_inodes(rd);
if (retval)
{
return retval;
}
}
else if (rd->new_inodes_per_group > rd->fs->super->s_inodes_per_group)
{
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))
{
printf("Requested number of inodes is too big, it requires %llu free blocks, "
"and there are only %llu free blocks available\n",
required_blocks, ext2fs_free_blocks_count(rd->fs->super));
return ENOENT;
}
retval = extend_move_blocks(rd);
if (retval)
{
return retval;
}
}
else
{
printf("The requested number of inodes is equal to current\n");
return 0;
}
retval = change_inode_numbers(rd);
if (retval)
{
return retval;
}
retval = change_super_and_bgd(rd);
if (retval)
{
return retval;
}
return 0;
}
__u32 atou(char *s)
{
__u32 x = 0;
if (s[0] == '0')
{
if (s[1] == 'x' || s[1] == 'X')
{
sscanf(s+2, "%x", &x);
}
else
{
sscanf(s+1, "%o", &x);
}
}
else
{
sscanf(s, "%u", &x);
}
return x;
}
const char *program_name = "realloc-inodes";
int main(int narg, char **args)
{
ext2_filsys fs;
io_manager io_ptr = unix_io_manager;
realloc_data rd = { 0 };
int optind, fd, retval, io_flags = 0, force = 0;
ext2fs_struct_stat st_buf;
char *device_name, *io_options;
optind = 1;
device_name = args[optind++];
add_error_table(&et_ext2_error_table);
fd = ext2fs_open_file(device_name, O_RDWR, 0);
if (fd < 0)
// USAGE: ./realloc-inodes <device> <new_count>
optind = 1;
rd.device_name = args[optind++];
rd.new_inode_count = atou(args[optind++]);
rd.fs_fd = ext2fs_open_file(rd.device_name, O_RDWR, 0);
if (rd.fs_fd < 0)
{
com_err("open", errno, _("while opening %s"), device_name);
com_err("open", errno, _("while opening %s"), rd.device_name);
exit(1);
}
retval = ext2fs_fstat(fd, &st_buf);
retval = ext2fs_fstat(rd.fs_fd, &st_buf);
if (retval < 0)
{
com_err("open", errno, _("while getting stat information for %s"), device_name);
com_err("open", errno, _("while getting stat information for %s"), rd.device_name);
exit(1);
}
if (!S_ISREG(st_buf.st_mode))
{
close(fd);
fd = -1;
close(rd.fs_fd);
rd.fs_fd = -1;
}
io_options = strchr(device_name, '?');
if (io_options)
rd.io_options = strchr(rd.device_name, '?');
if (rd.io_options)
{
*io_options++ = 0;
*rd.io_options++ = 0;
}
//io_flags = EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE;
io_flags |= EXT2_FLAG_64BITS;
retval = ext2fs_open2(device_name, io_options, io_flags, 0, 0, io_ptr, &fs);
retval = ext2fs_open2(rd.device_name, rd.io_options, io_flags, 0, 0, unix_io_manager, &rd.fs);
if (retval)
{
com_err(program_name, retval, _("while trying to open %s"), device_name);
com_err(program_name, retval, _("while trying to open %s"), rd.device_name);
printf(_("Couldn't find valid filesystem superblock.\n"));
exit(1);
}
if (!force && ((fs->super->s_state & EXT2_ERROR_FS) || ((fs->super->s_state & EXT2_VALID_FS) == 0)))
if (!force && ((rd.fs->super->s_state & EXT2_ERROR_FS) || ((rd.fs->super->s_state & EXT2_VALID_FS) == 0)))
{
fprintf(stderr, _("Please run 'e2fsck -f %s' first.\n\n"), device_name);
fprintf(stderr, _("Please run 'e2fsck -f %s' first.\n\n"), rd.device_name);
exit(1);
}
test(fs);
ext2fs_close(fs);
if (fd > 0)
do_realloc(&rd);
ext2fs_close(rd.fs);
if (rd.fs_fd > 0)
{
close(fd);
close(rd.fs_fd);
}
}