Makefile.in, .del-inodemap.c~24510e64, main.c, resize2fs.c, resize2fs.h:
New snapshot (almost fully functional)
diff --git a/resize/Makefile.in b/resize/Makefile.in
index 9f5c2cc..d5991f8 100644
--- a/resize/Makefile.in
+++ b/resize/Makefile.in
@@ -14,9 +14,10 @@
PROGS= resize2fs
MANPAGES= resize2fs.8
-RESIZE_OBJS= resize2fs.o main.o
+RESIZE_OBJS= inodemap.o resize2fs.o main.o
-SRCS= $(srcdir)/resize2fs.c \
+SRCS= $(srcdir)/inodemap.c \
+ $(srcdir)/resize2fs.c \
$(srcdir)/main.c
LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR) $(LIBUUID)
diff --git a/resize/inodemap.c b/resize/inodemap.c
new file mode 100644
index 0000000..9dc3db2
--- /dev/null
+++ b/resize/inodemap.c
@@ -0,0 +1,240 @@
+/*
+ * inodemap.c --- ext2resizer indoe mapper
+ *
+ * Copyright (C) 1997 Theodore Ts'o
+ *
+ * %Begin-Header%
+ * All rights reserved.
+ * %End-Header%
+ */
+
+#include "resize2fs.h"
+
+struct inode_map_entry {
+ ino_t old, new;
+};
+
+struct inode_map_struct {
+ struct inode_map_entry *list;
+ int size;
+ int num;
+ int sorted;
+};
+
+typedef struct inode_map_struct *inode_map;
+
+/*
+ * Create inode map table
+ */
+static errcode_t create_inode_map(inode_map *imap, int size)
+{
+ inode_map new;
+
+ new = malloc(sizeof(struct inode_map_struct));
+ if (!new)
+ return ENOMEM;
+ memset(new, 0, sizeof(struct inode_map_struct));
+
+ new->size = size ? size : 50;
+ new->num = 0;
+ new->sorted = 1;
+
+ new->list = malloc(sizeof(struct inode_map_struct) * new->size);
+ if (!new->list) {
+ free(new);
+ return ENOMEM;
+ }
+ *imap = new;
+ return 0;
+}
+
+/*
+ * Add an entry to the inode table map
+ */
+static errcode_t add_inode_map_entry(inode_map imap, ino_t old, ino_t new)
+{
+ struct inode_map_entry *p;
+ int newsize;
+
+ if (imap->num >= imap->size) {
+ newsize = imap->size + 100;
+ p = realloc(imap->list,
+ sizeof(struct inode_map_struct) * newsize);
+ if (!p)
+ return ENOMEM;
+ imap->list = p;
+ imap->size = newsize;
+ }
+ if (imap->num) {
+ if (imap->list[imap->num-1].old > old)
+ imap->sorted = 0;
+ }
+ imap->list[imap->num].old = old;
+ imap->list[imap->num].new = new;
+ imap->num++;
+ return 0;
+}
+
+/*
+ * Helper function for qsort
+ */
+static int inode_map_cmp(const void *a, const void *b)
+{
+ const struct inode_map_entry *db_a =
+ (const struct inode_map_entry *) a;
+ const struct inode_map_entry *db_b =
+ (const struct inode_map_entry *) b;
+
+ return (db_a->old - db_b->old);
+}
+
+/*
+ * Given an inode map and inode number, look up the old inode number
+ * and return the new inode number
+ */
+static ino_t inode_map_translate(inode_map imap, ino_t old)
+{
+ int low, high, mid;
+ ino_t lowval, highval;
+ float range;
+
+ if (!imap->sorted) {
+ qsort(imap->list, imap->num,
+ sizeof(struct inode_map_entry), inode_map_cmp);
+ imap->sorted = 1;
+ }
+ low = 0;
+ high = imap->num-1;
+ while (low <= high) {
+#if 0
+ mid = (low+high)/2;
+#else
+ if (low == high)
+ mid = low;
+ else {
+ /* Interpolate for efficiency */
+ lowval = imap->list[low].old;
+ highval = imap->list[high].old;
+
+ if (old < lowval)
+ range = 0;
+ else if (old > highval)
+ range = 1;
+ else
+ range = ((float) (old - lowval)) /
+ (highval - lowval);
+ mid = low + ((int) (range * (high-low)));
+ }
+#endif
+ if (old == imap->list[mid].old)
+ return imap->list[mid].new;
+ if (old < imap->list[mid].old)
+ high = mid-1;
+ else
+ low = mid+1;
+ }
+ return 0;
+}
+
+int check_and_change_inodes(ino_t dir, int entry,
+ struct ext2_dir_entry *dirent, int offset,
+ int blocksize, char *buf, void *private)
+{
+ inode_map imap = private;
+ ino_t new;
+
+ if (!dirent->inode)
+ return 0;
+
+ new = inode_map_translate(imap, dirent->inode);
+
+ if (!new)
+ return 0;
+
+ printf("Inode translate (dir=%ld, name=%.*s, %ld->%ld)\n",
+ dir, dirent->name_len, dirent->name, dirent->inode, new);
+
+ dirent->inode = new;
+
+ return DIRENT_CHANGED;
+}
+
+errcode_t ext2fs_inode_move(ext2_resize_t rfs)
+{
+ ino_t ino, start, end, new;
+ struct ext2_inode inode;
+ ext2_inode_scan scan;
+ inode_map imap;
+ errcode_t retval;
+ int group;
+
+ if (rfs->old_fs->group_desc_count <=
+ rfs->new_fs->group_desc_count)
+ return 0;
+
+ retval = create_inode_map(&imap, 0);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_inode_scan_goto_blockgroup(scan,
+ rfs->new_fs->group_desc_count);
+ if (retval) {
+ ext2fs_close_inode_scan(scan);
+ return retval;
+ }
+
+ new = EXT2_FIRST_INODE(rfs->new_fs->super);
+
+ /*
+ * First, copy all of the inodes that need to be moved
+ * elsewhere in the inode table
+ */
+ while (1) {
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval)
+ return retval;
+ if (!ino)
+ break;
+
+ if (!ext2fs_test_inode_bitmap(rfs->old_fs->inode_map, ino))
+ continue;
+
+ /*
+ * Find a new inode
+ */
+ while (1) {
+ if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map,
+ new))
+ break;
+ new++;
+ if (new > rfs->new_fs->super->s_inodes_count)
+ return ENOSPC;
+ }
+ ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new);
+ retval = ext2fs_write_inode(rfs->old_fs, new, &inode);
+ if (retval)
+ return retval;
+ group = (new-1) / EXT2_INODES_PER_GROUP(rfs->new_fs->super);
+ if (LINUX_S_ISDIR(inode.i_mode))
+ rfs->new_fs->group_desc[group].bg_used_dirs_count++;
+
+ printf("inode %ld->%ld\n", ino, new);
+
+ add_inode_map_entry(imap, ino, new);
+ }
+ /*
+ * Now, we iterate over all of the directories to update the
+ * inode references
+ */
+ retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist, 0, 0,
+ check_and_change_inodes, imap);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
diff --git a/resize/main.c b/resize/main.c
index d8b2200..9a53e74 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -49,7 +49,7 @@
device_name = argv[optind++];
new_size = atoi(argv[optind++]);
initialize_ext2_error_table();
-#if 0
+#if 1
io_ptr = unix_io_manager;
#else
io_ptr = test_io_manager;
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index b2fbc68..805a64c 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -200,7 +200,7 @@
*/
static errcode_t determine_relocations(ext2_resize_t rfs)
{
- int i, j;
+ int i, j, max, adj;
blk_t blk, group_blk;
unsigned long old_blocks, new_blocks;
errcode_t retval;
@@ -229,6 +229,9 @@
if (old_blocks == new_blocks)
return 0;
+ max = fs->group_desc_count;
+ if (max > rfs->old_fs->group_desc_count)
+ max = rfs->old_fs->group_desc_count;
group_blk = rfs->old_fs->super->s_first_data_block;
/*
* If we're reducing the number of descriptor blocks, this
@@ -236,15 +239,17 @@
* blocks as free.
*/
if (old_blocks > new_blocks) {
- for (i = 0; i < fs->group_desc_count; i++) {
+ for (i = 0; i < max; i++) {
if (!ext2fs_bg_has_super(fs, i)) {
group_blk += fs->super->s_blocks_per_group;
continue;
}
for (blk = group_blk+1+old_blocks;
- blk < group_blk+1+new_blocks; blk++)
+ blk < group_blk+1+new_blocks; blk++) {
ext2fs_unmark_block_bitmap(fs->block_map,
blk);
+ rfs->needed_blocks--;
+ }
group_blk += fs->super->s_blocks_per_group;
}
return 0;
@@ -253,7 +258,7 @@
* If we're increasing the number of descriptor blocks, life
* gets interesting....
*/
- for (i = 0; i < fs->group_desc_count; i++) {
+ for (i = 0; i < max; i++) {
if (!ext2fs_bg_has_super(fs, i))
goto next_group;
@@ -266,11 +271,14 @@
* Check to see if we overlap with the inode
* or block bitmap
*/
- if (blk == fs->group_desc[i].bg_inode_bitmap)
- fs->group_desc[i].bg_block_bitmap = 0;
- if (blk == fs->group_desc[i].bg_inode_bitmap)
+ if (blk == fs->group_desc[i].bg_block_bitmap) {
+ fs->group_desc[i].bg_block_bitmap = 0;
+ rfs->needed_blocks++;
+ }
+ if (blk == fs->group_desc[i].bg_inode_bitmap) {
fs->group_desc[i].bg_inode_bitmap = 0;
-
+ rfs->needed_blocks++;
+ }
/*
* Check to see if we overlap with the inode
* table
@@ -320,28 +328,179 @@
ext2fs_mark_block_bitmap(fs->block_map,
fs->group_desc[i].bg_inode_bitmap);
+ /*
+ * The inode table, if we need to relocate it, is
+ * handled specially. We have to reserve the blocks
+ * for both the old and the new inode table, since we
+ * can't have the inode table be destroyed during the
+ * block relocation phase.
+ */
+ adj = fs->group_desc[i].bg_inode_table -
+ rfs->old_fs->group_desc[i].bg_inode_table;
+ if (!adj)
+ goto next_group; /* inode table not moved */
+
+ /*
+ * Figure out how many blocks we need to have free.
+ * This takes into account that we need to reserve
+ * both inode tables, which may be overallping.
+ */
+ if (adj < 0)
+ adj = -adj;
+ if (adj > fs->inode_blocks_per_group)
+ adj = fs->inode_blocks_per_group;
+ rfs->needed_blocks += fs->inode_blocks_per_group + adj;
+
+ /*
+ * Mark the new inode table as in use in the new block
+ * allocation bitmap.
+ */
for (blk = fs->group_desc[i].bg_inode_table, j=0;
j < fs->inode_blocks_per_group ; j++, blk++)
ext2fs_mark_block_bitmap(fs->block_map, blk);
-
/*
- * Mark the inode tables which will need to move, and
- * restore the old inode table location (for now)
+ * Make sure the old inode table is reserved in the
+ * block reservation bitmap.
*/
- if (fs->group_desc[i].bg_inode_table !=
- rfs->old_fs->group_desc[i].bg_inode_table) {
- rfs->move_itable[i] = fs->group_desc[i].bg_inode_table;
- fs->group_desc[i].bg_inode_table =
- rfs->old_fs->group_desc[i].bg_inode_table;
- }
+ for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
+ j < fs->inode_blocks_per_group ; j++, blk++)
+ ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
next_group:
group_blk += rfs->new_fs->super->s_blocks_per_group;
}
+ return 0;
}
/*
+ * A very scary routine --- this one moves the inode table around!!!
+ *
+ * After this you have to use the rfs->new_fs file handle to read and
+ * write inodes.
+ */
+errcode_t move_itables(ext2_resize_t rfs)
+{
+ int i, max;
+ ext2_filsys fs = rfs->new_fs;
+ char *buf;
+ blk_t old, new;
+ errcode_t retval, err;
+
+ printf("Hide the women and children --- "
+ "commencing inode table moves!!\n");
+
+ max = fs->group_desc_count;
+ if (max > rfs->old_fs->group_desc_count)
+ max = rfs->old_fs->group_desc_count;
+
+ buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
+ if (!buf)
+ return ENOMEM;
+
+ for (i=0; i < max; i++) {
+ old = rfs->old_fs->group_desc[i].bg_inode_table;
+ new = fs->group_desc[i].bg_inode_table;
+
+ printf("Group %d block %ld->%ld\n", i, old, new);
+
+ if (old == new)
+ continue;
+
+ retval = io_channel_read_blk(fs->io, old,
+ fs->inode_blocks_per_group, buf);
+ if (retval)
+ goto backout;
+ retval = io_channel_write_blk(fs->io, new,
+ fs->inode_blocks_per_group, buf);
+ if (retval) {
+ io_channel_write_blk(fs->io, old,
+ fs->inode_blocks_per_group, buf);
+ goto backout;
+ }
+ }
+ ext2fs_flush(rfs->new_fs);
+ printf("Inode table move finished.\n");
+ return 0;
+
+backout:
+ printf("Error: %s; now backing out!\n", error_message(retval));
+ while (--i >= 0) {
+ printf("Group %d block %ld->%ld\n", i, new, old);
+ old = rfs->old_fs->group_desc[i].bg_inode_table;
+ new = fs->group_desc[i].bg_inode_table;
+
+ err = io_channel_read_blk(fs->io, new,
+ fs->inode_blocks_per_group, buf);
+ if (err)
+ continue;
+ err = io_channel_write_blk(fs->io, old,
+ fs->inode_blocks_per_group, buf);
+ }
+ return retval;
+}
+
+/*
+ * Finally, recalculate the summary information
+ */
+static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
+{
+ blk_t blk;
+ ino_t ino;
+ int group = 0;
+ int count = 0;
+ int total_free = 0;
+ int group_free = 0;
+
+ /*
+ * First calculate the block statistics
+ */
+ for (blk = fs->super->s_first_data_block;
+ blk < fs->super->s_blocks_count; blk++) {
+ if (!ext2fs_fast_test_block_bitmap(fs->block_map, blk)) {
+ group_free++;
+ total_free++;
+ }
+ count++;
+ if ((count == fs->super->s_blocks_per_group) ||
+ (blk == fs->super->s_blocks_count-1)) {
+ fs->group_desc[group++].bg_free_blocks_count =
+ group_free;
+ count = 0;
+ group_free = 0;
+ }
+ }
+ fs->super->s_free_blocks_count = total_free;
+
+ /*
+ * Next, calculate the inode statistics
+ */
+ group_free = 0;
+ total_free = 0;
+ count = 0;
+ group = 0;
+ for (ino = 1; ino <= fs->super->s_inodes_count; ino++) {
+ if (!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
+ group_free++;
+ total_free++;
+ }
+ count++;
+ if ((count == fs->super->s_inodes_per_group) ||
+ (ino == fs->super->s_inodes_count)) {
+ fs->group_desc[group++].bg_free_inodes_count =
+ group_free;
+ count = 0;
+ group_free = 0;
+ }
+ }
+ fs->super->s_free_inodes_count = total_free;
+ ext2fs_mark_super_dirty(fs);
+ return 0;
+}
+
+
+
+/*
* This is the top-level routine which does the dirty deed....
*/
errcode_t resize_fs(ext2_filsys fs, blk_t new_size)
@@ -361,13 +520,6 @@
return ENOMEM;
memset(rfs, 0, sizeof(struct ext2_resize_struct));
- rfs->move_itable = malloc(sizeof(blk_t) * fs->group_desc_count);
- if (!rfs->move_itable) {
- retval = ENOMEM;
- goto errout;
- }
- memset(rfs->move_itable, 0, sizeof(blk_t) * fs->group_desc_count);
-
rfs->old_fs = fs;
retval = ext2fs_dup_handle(fs, &rfs->new_fs);
if (retval)
@@ -381,6 +533,14 @@
if (retval)
goto errout;
+ printf("Number of free blocks: %d, Needed: %d\n",
+ fs->super->s_free_blocks_count, rfs->needed_blocks);
+
+ if (rfs->needed_blocks > fs->super->s_free_blocks_count) {
+ retval = ENOSPC;
+ goto errout;
+ }
+
printf("\nOld superblock:\n");
list_super(rfs->old_fs->super);
printf("\n\nNew superblock:\n");
@@ -388,8 +548,23 @@
printf("\n");
retval = ext2fs_move_blocks(rfs->old_fs, rfs->reserve_blocks,
+ rfs->new_fs->block_map,
EXT2_BMOVE_GET_DBLIST);
+ if (retval)
+ return retval;
+ retval = ext2fs_inode_move(rfs);
+ if (retval)
+ return retval;
+
+ retval = move_itables(rfs);
+ if (retval)
+ return retval;
+
+ retval = ext2fs_calculate_summary_stats(rfs->new_fs);
+ if (retval)
+ return retval;
+
retval = ext2fs_close(rfs->new_fs);
if (retval)
return retval;
@@ -399,11 +574,8 @@
return 0;
errout:
- if (rfs->move_itable)
- free(rfs->move_itable);
if (rfs->new_fs)
ext2fs_free(rfs->new_fs);
free(rfs);
return retval;
}
-
diff --git a/resize/resize2fs.h b/resize/resize2fs.h
index 5c1dad3..cc50004 100644
--- a/resize/resize2fs.h
+++ b/resize/resize2fs.h
@@ -41,11 +41,6 @@
ext2_brel block_relocate;
ext2fs_block_bitmap reserve_blocks;
int needed_blocks;
- /*
- * This array contains the new location of the inode table for
- * those block groups where it has to be relocated.
- */
- blk_t *move_itable;
};
typedef struct ext2_resize_struct *ext2_resize_t;