Many files:
bmove.c (ext2fs_move_blocks): New function which takes a bitmap of
blocks which need to be moved, and moves those blocks to another
location in the filesystem.
rs_bitmap.c (ext2fs_resize_generic_bitmap): When expanding a bitmap,
make sure all of the new parts of the bitmap are zero.
bitmaps.c (ext2fs_copy_bitmap): Fix bug; the destination bitmap wasn't
being returned to the caller.
alloc_tables.c (ext2fs_allocate_group_table): Add new function
ext2fs_allocate_group_table() which sets the group tables for a
particular block group. The relevant code was factored out of
ext2fs_allocate_tables().
dblist.c (make_dblist): Adjust the initial size of the directory block
list to be a bit more realize (ten plus twice the number of
directories in the filesystem).
Check in interim work.
diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog
index f8fb703..b9f4177 100644
--- a/lib/ext2fs/ChangeLog
+++ b/lib/ext2fs/ChangeLog
@@ -1,3 +1,27 @@
+Mon Jun 9 10:45:48 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * bmove.c (ext2fs_move_blocks): New function which takes a bitmap
+ of blocks which need to be moved, and moves those blocks
+ to another location in the filesystem.
+
+ * rs_bitmap.c (ext2fs_resize_generic_bitmap): When expanding a
+ bitmap, make sure all of the new parts of the bitmap are
+ zero.
+
+Sun Jun 8 16:24:39 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
+
+ * bitmaps.c (ext2fs_copy_bitmap): Fix bug; the destination bitmap
+ wasn't being returned to the caller.
+
+ * alloc_tables.c (ext2fs_allocate_group_table): Add new function
+ ext2fs_allocate_group_table() which sets the group tables
+ for a particular block group. The relevant code was
+ factored out of ext2fs_allocate_tables().
+
+ * dblist.c (make_dblist): Adjust the initial size of the directory
+ block list to be a bit more realize (ten plus twice the
+ number of directories in the filesystem).
+
Thu May 8 22:19:09 1997 Theodore Ts'o <tytso@rsts-11.mit.edu>
* badblocks.c (ext2fs_badblocks_list_test): Fix bug where
diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in
index 4e220c6..a43f814 100644
--- a/lib/ext2fs/Makefile.in
+++ b/lib/ext2fs/Makefile.in
@@ -16,6 +16,7 @@
bitmaps.o \
bitops.o \
block.o \
+ bmove.o \
brel_ma.o \
check_desc.o \
closefs.o \
@@ -64,6 +65,7 @@
$(srcdir)/bitops.c \
$(srcdir)/block.c \
$(srcdir)/brel_ma.c \
+ $(srcdir)/bmove.c \
$(srcdir)/check_desc.c \
$(srcdir)/closefs.c \
$(srcdir)/cmp_bitmaps.c \
diff --git a/lib/ext2fs/alloc_tables.c b/lib/ext2fs/alloc_tables.c
index 6a60bf7..1c88557 100644
--- a/lib/ext2fs/alloc_tables.c
+++ b/lib/ext2fs/alloc_tables.c
@@ -26,65 +26,87 @@
#include "ext2fs.h"
-errcode_t ext2fs_allocate_tables(ext2_filsys fs)
+errcode_t ext2fs_allocate_group_table(ext2_filsys fs, int group,
+ ext2fs_block_bitmap bmap)
{
errcode_t retval;
blk_t group_blk, start_blk, last_blk, new_blk, blk;
- int i, j;
+ int j;
- group_blk = fs->super->s_first_data_block;
- for (i = 0; i < fs->group_desc_count; i++) {
- last_blk = group_blk + fs->super->s_blocks_per_group;
- if (last_blk >= fs->super->s_blocks_count)
- last_blk = fs->super->s_blocks_count - 1;
+ group_blk = fs->super->s_first_data_block +
+ (group * fs->super->s_blocks_per_group);
+
+ last_blk = group_blk + fs->super->s_blocks_per_group;
+ if (last_blk >= fs->super->s_blocks_count)
+ last_blk = fs->super->s_blocks_count - 1;
- /*
- * Allocate the inode table
- */
- start_blk = group_blk + 3 + fs->desc_blocks;
- if (start_blk > last_blk)
- start_blk = group_blk;
+ start_blk = group_blk + 3 + fs->desc_blocks;
+ if (start_blk > last_blk)
+ start_blk = group_blk;
+
+ if (!bmap)
+ bmap = fs->block_map;
+
+ /*
+ * Allocate the inode table
+ */
+ if (!fs->group_desc[group].bg_inode_table) {
retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
fs->inode_blocks_per_group,
- fs->block_map, &new_blk);
+ bmap, &new_blk);
if (retval)
return retval;
for (j=0, blk = new_blk;
j < fs->inode_blocks_per_group;
j++, blk++)
- ext2fs_mark_block_bitmap(fs->block_map, blk);
- fs->group_desc[i].bg_inode_table = new_blk;
+ ext2fs_mark_block_bitmap(bmap, blk);
+ fs->group_desc[group].bg_inode_table = new_blk;
+ }
- /*
- * Allocate the block and inode bitmaps
- */
- if (fs->stride) {
- start_blk += fs->inode_blocks_per_group;
- start_blk += ((fs->stride * i) %
- (last_blk - start_blk));
- if (start_blk > last_blk)
- /* should never happen */
- start_blk = group_blk;
- } else
+ /*
+ * Allocate the block and inode bitmaps, if necessary
+ */
+ if (fs->stride) {
+ start_blk += fs->inode_blocks_per_group;
+ start_blk += ((fs->stride * group) %
+ (last_blk - start_blk));
+ if (start_blk > last_blk)
+ /* should never happen */
start_blk = group_blk;
+ } else
+ start_blk = group_blk;
+
+ if (!fs->group_desc[group].bg_block_bitmap) {
retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
- 1, fs->block_map, &new_blk);
+ 1, bmap, &new_blk);
if (retval)
return retval;
- ext2fs_mark_block_bitmap(fs->block_map, new_blk);
- fs->group_desc[i].bg_block_bitmap = new_blk;
+ ext2fs_mark_block_bitmap(bmap, new_blk);
+ fs->group_desc[group].bg_block_bitmap = new_blk;
+ }
+ if (!fs->group_desc[group].bg_inode_bitmap) {
retval = ext2fs_get_free_blocks(fs, start_blk, last_blk,
- 1, fs->block_map, &new_blk);
+ 1, bmap, &new_blk);
if (retval)
return retval;
- ext2fs_mark_block_bitmap(fs->block_map, new_blk);
- fs->group_desc[i].bg_inode_bitmap = new_blk;
+ ext2fs_mark_block_bitmap(bmap, new_blk);
+ fs->group_desc[group].bg_inode_bitmap = new_blk;
+ }
+ return 0;
+}
- /*
- * Increment the start of the block group
- */
- group_blk += fs->super->s_blocks_per_group;
+
+
+errcode_t ext2fs_allocate_tables(ext2_filsys fs)
+{
+ errcode_t retval;
+ int i;
+
+ for (i = 0; i < fs->group_desc_count; i++) {
+ retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
+ if (retval)
+ return retval;
}
return 0;
}
diff --git a/lib/ext2fs/bitmaps.c b/lib/ext2fs/bitmaps.c
index c3a778d..defa0cd 100644
--- a/lib/ext2fs/bitmaps.c
+++ b/lib/ext2fs/bitmaps.c
@@ -91,6 +91,7 @@
new->magic = src->magic;
new->fs = src->fs;
new->base_error_code = src->base_error_code;
+ *dest = new;
return 0;
}
diff --git a/lib/ext2fs/bmove.c b/lib/ext2fs/bmove.c
new file mode 100644
index 0000000..8e8ad48
--- /dev/null
+++ b/lib/ext2fs/bmove.c
@@ -0,0 +1,148 @@
+/*
+ * bmove.c --- Move blocks around to make way for a particular
+ * filesystem structure.
+ *
+ * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <linux/ext2_fs.h>
+#include "ext2fs/ext2fs.h"
+
+struct process_block_struct {
+ ino_t ino;
+ struct ext2_inode * inode;
+ ext2fs_block_bitmap reserve;
+ errcode_t error;
+ char *buf;
+ int add_dir;
+};
+
+static int process_block(ext2_filsys fs, blk_t *block_nr,
+ int blockcnt, blk_t ref_block,
+ int ref_offset, void *private)
+{
+ struct process_block_struct *pb = private;
+ errcode_t retval;
+ int ret;
+ blk_t block, orig;
+
+ block = orig = *block_nr;
+ ret = 0;
+
+ /*
+ * Let's see if this is one which we need to relocate
+ */
+ if (ext2fs_test_block_bitmap(pb->reserve, block)) {
+ do {
+ if (++block >= fs->super->s_blocks_count)
+ block = fs->super->s_first_data_block;
+ if (block == orig) {
+ pb->error = ENOSPC;
+ return BLOCK_ABORT;
+ }
+ } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
+ ext2fs_test_block_bitmap(fs->block_map, block));
+
+ retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
+ if (retval) {
+ pb->error = retval;
+ return BLOCK_ABORT;
+ }
+ retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
+ if (retval) {
+ pb->error = retval;
+ return BLOCK_ABORT;
+ }
+ *block_nr = block;
+ ext2fs_mark_block_bitmap(fs->block_map, block);
+ ret = BLOCK_CHANGED;
+ printf("ino=%ld, blockcnt=%d, %ld->%ld\n", pb->ino,
+ blockcnt, orig, block);
+ }
+ if (pb->add_dir) {
+ retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
+ block, blockcnt);
+ if (retval) {
+ pb->error = retval;
+ ret |= BLOCK_ABORT;
+ }
+ }
+ return ret;
+}
+
+errcode_t ext2fs_move_blocks(ext2_filsys fs,
+ ext2fs_block_bitmap reserve,
+ int flags)
+{
+ ino_t ino;
+ struct ext2_inode inode;
+ errcode_t retval;
+ struct process_block_struct pb;
+ ext2_inode_scan scan;
+ char *block_buf;
+
+ retval = ext2fs_open_inode_scan(fs, 0, &scan);
+ if (retval)
+ return retval;
+
+ pb.reserve = reserve;
+ pb.error = 0;
+
+ block_buf = malloc(fs->blocksize * 4);
+ if (!block_buf)
+ return ENOMEM;
+ pb.buf = block_buf + fs->blocksize * 3;
+
+ /*
+ * If GET_DBLIST is set in the flags field, then we should
+ * gather directory block information while we're doing the
+ * block move.
+ */
+ if (flags & EXT2_BMOVE_GET_DBLIST) {
+ if (fs->dblist) {
+ ext2fs_free_dblist(fs->dblist);
+ fs->dblist = NULL;
+ }
+ retval = ext2fs_init_dblist(fs, 0);
+ if (retval)
+ return retval;
+ }
+
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval)
+ return retval;
+
+ while (ino) {
+ if ((inode.i_links_count == 0) ||
+ !ext2fs_inode_has_valid_blocks(&inode))
+ goto next;
+
+ pb.ino = ino;
+ pb.inode = &inode;
+
+ pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
+ flags & EXT2_BMOVE_GET_DBLIST);
+
+ retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+ process_block, &pb);
+ if (retval)
+ return retval;
+ if (pb.error)
+ return pb.error;
+
+ next:
+ retval = ext2fs_get_next_inode(scan, &ino, &inode);
+ if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+ goto next;
+ }
+ return 0;
+}
+
diff --git a/lib/ext2fs/brel.h b/lib/ext2fs/brel.h
index f31b7ae..22089c3 100644
--- a/lib/ext2fs/brel.h
+++ b/lib/ext2fs/brel.h
@@ -19,7 +19,9 @@
} owner;
};
-#define RELOCATE_INODE_REF 0x0001
+#define RELOCATE_TYPE_REF 0x0007
+#define RELOCATE_BLOCK_REF 0x0001
+#define RELOCATE_INODE_REF 0x0002
typedef struct ext2_block_relocation_table *ext2_brel;
diff --git a/lib/ext2fs/dblist.c b/lib/ext2fs/dblist.c
index f990c10..80e1f05 100644
--- a/lib/ext2fs/dblist.c
+++ b/lib/ext2fs/dblist.c
@@ -77,6 +77,7 @@
retval = ext2fs_get_num_dirs(fs, &dblist->size);
if (retval)
goto cleanup;
+ dblist->size = (dblist->size * 2) + 12;
}
len = sizeof(struct ext2_db_entry) * dblist->size;
dblist->count = count;
diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
index 2e68c4c..f3d136a 100644
--- a/lib/ext2fs/ext2fs.h
+++ b/lib/ext2fs/ext2fs.h
@@ -199,6 +199,11 @@
#define BLOCK_COUNT_TRANSLATOR (-4)
/*
+ * Flags for ext2fs_move_blocks
+ */
+#define EXT2_BMOVE_GET_DBLIST 0x0001
+
+/*
* Return flags for the directory iterator functions
*/
#define DIRENT_CHANGED 1
@@ -373,8 +378,10 @@
ext2fs_block_bitmap map,
blk_t *ret);
-/* allocate_tables.c */
-errcode_t ext2fs_allocate_tables(ext2_filsys fs);
+/* alloc_tables.c */
+extern errcode_t ext2fs_allocate_tables(ext2_filsys fs);
+extern errcode_t ext2fs_allocate_group_table(ext2_filsys fs, int group,
+ ext2fs_block_bitmap bmap);
/* badblocks.c */
extern errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret,
@@ -454,6 +461,11 @@
void *private),
void *private);
+/* bmove.c */
+extern errcode_t ext2fs_move_blocks(ext2_filsys fs,
+ ext2fs_block_bitmap reserve,
+ int flags);
+
/* check_desc.c */
extern errcode_t ext2fs_check_desc(ext2_filsys fs);
diff --git a/lib/ext2fs/rs_bitmap.c b/lib/ext2fs/rs_bitmap.c
index 9017853..c41b5e6 100644
--- a/lib/ext2fs/rs_bitmap.c
+++ b/lib/ext2fs/rs_bitmap.c
@@ -30,12 +30,24 @@
{
size_t size, new_size;
char *new_bitmap;
+ __u32 bitno;
if (!bmap)
return EINVAL;
EXT2_CHECK_MAGIC(bmap, EXT2_ET_MAGIC_GENERIC_BITMAP);
-
+
+ /*
+ * If we're expanding the bitmap, make sure all of the new
+ * parts of the bitmap are zero.
+ */
+ if (new_end > bmap->end) {
+ bitno = bmap->real_end;
+ if (bitno > new_end)
+ bitno = new_end;
+ for (; bitno > bmap->end; bitno--)
+ ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
+ }
if (new_real_end == bmap->real_end) {
bmap->end = new_end;
return 0;
diff --git a/resize/Makefile.in b/resize/Makefile.in
index a57ee3b..9f5c2cc 100644
--- a/resize/Makefile.in
+++ b/resize/Makefile.in
@@ -14,14 +14,13 @@
PROGS= resize2fs
MANPAGES= resize2fs.8
-RESIZE_OBJS= banalysis.o resize2fs.o main.o
+RESIZE_OBJS= resize2fs.o main.o
-SRCS= $(srcdir)/banalysis.c \
- $(srcdir)/resize2fs.c \
+SRCS= $(srcdir)/resize2fs.c \
$(srcdir)/main.c
-LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
-DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
+LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR) $(LIBUUID)
+DEPLIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR) $(LIBUUID)
.c.o:
$(CC) -c $(ALL_CFLAGS) $< -o $@
diff --git a/resize/NOTES b/resize/NOTES
new file mode 100644
index 0000000..e04d180
--- /dev/null
+++ b/resize/NOTES
@@ -0,0 +1,8 @@
+TODO
+
+*) Inode table relocation
+
+*) Inode relocation
+
+*) Summary information collection
+
diff --git a/resize/banalysis.c b/resize/banalysis.c
index 233158b..5b02d22 100644
--- a/resize/banalysis.c
+++ b/resize/banalysis.c
@@ -1,5 +1,5 @@
/*
- * banalysis.c --- Analyze a filesystem for a block struct
+ * banalysis.c --- Analyze a filesystem by block
*
* Copyright (C) 1997 Theodore Ts'o. This file may be redistributed
* under the terms of the GNU Public License.
@@ -12,9 +12,6 @@
#include <sys/types.h>
#include <sys/time.h>
-#ifdef HAVE_LINUX_FS_H
-#include <linux/fs.h>
-#endif
#include <linux/ext2_fs.h>
#include "ext2fs/ext2fs.h"
@@ -28,31 +25,6 @@
void *private;
};
-/*
- * This function returns 1 if the inode's block entries actually
- * contain block entries.
- */
-static int inode_has_valid_blocks(struct ext2_inode *inode)
-{
- /*
- * Only directories, regular files, and some symbolic links
- * have valid block entries.
- */
- if (!LINUX_S_ISDIR(inode->i_mode) && !LINUX_S_ISREG(inode->i_mode) &&
- !LINUX_S_ISLNK(inode->i_mode))
- return 0;
-
- /*
- * If the symbolic link is a "fast symlink", then the symlink
- * target is stored in the block entries.
- */
- if (LINUX_S_ISLNK (inode->i_mode) && inode->i_blocks == 0 &&
- inode->i_size < EXT2_N_BLOCKS * sizeof (unsigned long))
- return 0;
-
- return 1;
-}
-
static int process_block(ext2_filsys fs, blk_t *block_nr,
int blockcnt, blk_t ref_block,
int ref_offset, void *private)
@@ -113,7 +85,7 @@
ctx.brel = block_relocation_table;
while (ino) {
if ((inode.i_links_count == 0) ||
- !inode_has_valid_blocks(&inode))
+ !ext2fs_inode_has_valid_blocks(&inode))
goto next;
ctx.ino = ino;
@@ -139,3 +111,4 @@
}
return 0;
}
+
diff --git a/resize/main.c b/resize/main.c
index b664664..d8b2200 100644
--- a/resize/main.c
+++ b/resize/main.c
@@ -49,13 +49,13 @@
device_name = argv[optind++];
new_size = atoi(argv[optind++]);
initialize_ext2_error_table();
-#if 1
+#if 0
io_ptr = unix_io_manager;
#else
io_ptr = test_io_manager;
test_io_backing_manager = unix_io_manager;
#endif
- retval = ext2fs_open (device_name, 0, 0, 0,
+ retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
io_ptr, &fs);
if (retval) {
com_err (program_name, retval, "while trying to open %s",
@@ -70,7 +70,11 @@
ext2fs_close (fs);
exit (1);
}
- resize_fs(fs, new_size);
- ext2fs_close (fs);
+ retval = resize_fs(fs, new_size);
+ if (retval) {
+ com_err(program_name, retval, "while trying to resize %s",
+ device_name);
+ ext2fs_close (fs);
+ }
exit (0);
}
diff --git a/resize/resize2fs.c b/resize/resize2fs.c
index 3c91547..b2fbc68 100644
--- a/resize/resize2fs.c
+++ b/resize/resize2fs.c
@@ -21,11 +21,16 @@
errcode_t retval;
ino_t real_end;
blk_t blk, group_block;
- unsigned long i;
+ unsigned long i, j;
struct ext2_group_desc *new;
+ char *buf;
+ int old_numblocks, numblocks, adjblocks;
fs = rfs->new_fs;
fs->super->s_blocks_count = new_size;
+ ext2fs_mark_super_dirty(fs);
+ ext2fs_mark_bb_dirty(fs);
+ ext2fs_mark_ib_dirty(fs);
retry:
fs->group_desc_count = (fs->super->s_blocks_count -
@@ -107,88 +112,122 @@
return ENOMEM;
fs->group_desc = new;
}
- group_block = rfs->old_fs->super->s_first_data_block;
- for (i = 0; i < fs->group_desc_count; i++) {
- if (i < rfs->old_fs->group_desc_count) {
- group_block += fs->super->s_blocks_per_group;
- continue;
+
+ /*
+ * Fix the count of the last (old) block group
+ */
+ if (rfs->old_fs->group_desc_count > fs->group_desc_count)
+ return 0;
+ old_numblocks = (rfs->old_fs->super->s_blocks_count -
+ rfs->old_fs->super->s_first_data_block) %
+ rfs->old_fs->super->s_blocks_per_group;
+ if (!old_numblocks)
+ old_numblocks = rfs->old_fs->super->s_blocks_per_group;
+ if (rfs->old_fs->group_desc_count == fs->group_desc_count) {
+ numblocks = (rfs->new_fs->super->s_blocks_count -
+ rfs->new_fs->super->s_first_data_block) %
+ rfs->new_fs->super->s_blocks_per_group;
+ if (!numblocks)
+ numblocks = rfs->new_fs->super->s_blocks_per_group;
+ } else
+ numblocks = rfs->new_fs->super->s_blocks_per_group;
+ i = rfs->old_fs->group_desc_count - 1;
+ fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
+
+ /*
+ * Initialize the new block group descriptors
+ */
+ if (rfs->old_fs->group_desc_count >= fs->group_desc_count)
+ return 0;
+ buf = malloc(fs->blocksize);
+ if (!buf)
+ return ENOMEM;
+ memset(buf, 0, fs->blocksize);
+ group_block = fs->super->s_first_data_block +
+ rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
+ for (i = rfs->old_fs->group_desc_count;
+ i < fs->group_desc_count; i++) {
+ memset(&fs->group_desc[i], 0,
+ sizeof(struct ext2_group_desc));
+ adjblocks = 0;
+
+ if (i == fs->group_desc_count-1) {
+ numblocks = (fs->super->s_blocks_count -
+ fs->super->s_first_data_block) %
+ fs->super->s_blocks_per_group;
+ if (!numblocks)
+ numblocks = fs->super->s_blocks_per_group;
+ } else
+ numblocks = fs->super->s_blocks_per_group;
+
+ if (ext2fs_bg_has_super(fs, i)) {
+ for (j=0; j < fs->desc_blocks+1; j++)
+ ext2fs_mark_block_bitmap(fs->block_map,
+ group_block + j);
+ adjblocks = 1 + fs->desc_blocks;
}
- /* XXXX */
+ adjblocks += 2 + fs->inode_blocks_per_group;
+
+ numblocks -= adjblocks;
+ fs->super->s_free_blocks_count -= adjblocks;
+ fs->super->s_free_inodes_count +=
+ fs->super->s_inodes_per_group;
+ fs->group_desc[i].bg_free_blocks_count = numblocks;
+ fs->group_desc[i].bg_free_inodes_count =
+ fs->super->s_inodes_per_group;
+ fs->group_desc[i].bg_used_dirs_count = 0;
+
+ retval = ext2fs_allocate_group_table(fs, i, 0);
+ if (retval)
+ return retval;
+
+ for (blk=fs->group_desc[i].bg_inode_table, j=0;
+ j < fs->inode_blocks_per_group;
+ blk++, j++) {
+ retval = io_channel_write_blk(fs->io, blk, 1, buf);
+ if (retval)
+ return retval;
+ }
+ group_block += fs->super->s_blocks_per_group;
}
-
return 0;
}
/*
- * This routine reserves a block in the new filesystem. If the block
- * is already used, we mark it as needing relocation. Otherwise, we
- * just mark it as used.
- */
-static reserve_block(ext2_resize_t rfs, blk_t blk)
-{
- if (ext2fs_test_block_bitmap(rfs->new_fs->block_map, blk))
- ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
- else
- ext2fs_mark_block_bitmap(rfs->new_fs->block_map, blk);
-}
-
-/*
- * This routine is a helper function for determine_relocations(). It
- * is called for each block group which has a superblock, and for
- * which we need to expand the size of the descriptor table. We have
- * to account for the fact that in some cases we will need to move the
- * inode table, which will mean moving or reserving blocks at the end
- * of the inode table, since the inode table will be moved down to
- * make space.
- *
- * "And the block group descriptors waddled across the street..."
- */
-static void make_way_for_descriptors(ext2_resize_t rfs,
- int block_group,
- blk_t group_blk)
-{
- blk_t blk, start_blk, end_blk, itable, move_by;
- unsigned long i;
- ext2_filsys fs;
-
- start_blk = group_blk + rfs->old_fs->desc_blocks + 1;
- end_blk = group_blk + rfs->new_fs->desc_blocks + 1;
- fs = rfs->new_fs;
- itable = fs->group_desc[block_group].bg_inode_table;
- if (end_blk > itable) {
- move_by = itable - end_blk;
- for (blk = itable, i=0; i < move_by; blk++, i++) {
- ext2fs_unmark_block_bitmap(fs->block_map, blk);
- reserve_block(rfs, blk+fs->inode_blocks_per_group);
- }
- end_blk -= move_by;
- fs->group_desc[i].bg_inode_table += move_by;
- }
- for (blk = start_blk; blk < end_blk; blk++)
- reserve_block(rfs, blk);
-}
-
-
-/*
* This routine marks and unmarks reserved blocks in the new block
* bitmap. It also determines which blocks need to be moved and
* places this information into the move_blocks bitmap.
*/
static errcode_t determine_relocations(ext2_resize_t rfs)
{
- int i;
+ int i, j;
blk_t blk, group_blk;
unsigned long old_blocks, new_blocks;
errcode_t retval;
+ ext2_filsys fs = rfs->new_fs;
retval = ext2fs_allocate_block_bitmap(rfs->old_fs,
"blocks to be moved",
- &rfs->move_blocks);
+ &rfs->reserve_blocks);
if (retval)
return retval;
+
+ /*
+ * If we're shrinking the filesystem, we need to move all of
+ * the blocks that don't fit any more
+ */
+ for (blk = fs->super->s_blocks_count;
+ blk < rfs->old_fs->super->s_blocks_count; blk++) {
+ if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk))
+ rfs->needed_blocks++;
+ ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
+ }
old_blocks = rfs->old_fs->desc_blocks;
- new_blocks = rfs->new_fs->desc_blocks;
+ new_blocks = fs->desc_blocks;
+
+ if (old_blocks == new_blocks)
+ return 0;
group_blk = rfs->old_fs->super->s_first_data_block;
/*
@@ -197,50 +236,111 @@
* blocks as free.
*/
if (old_blocks > new_blocks) {
- for (i = 0; i < rfs->new_fs->group_desc_count; i++) {
- if (!ext2fs_bg_has_super(rfs->new_fs, i)) {
- group_blk += rfs->new_fs->super->s_blocks_per_group;
+ for (i = 0; i < fs->group_desc_count; 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++)
- ext2fs_unmark_block_bitmap(rfs->new_fs->block_map,
+ ext2fs_unmark_block_bitmap(fs->block_map,
blk);
- group_blk += rfs->new_fs->super->s_blocks_per_group;
+ group_blk += fs->super->s_blocks_per_group;
}
+ return 0;
}
/*
* If we're increasing the number of descriptor blocks, life
- * gets interesting. In some cases, we will need to move the
- * inode table.
+ * gets interesting....
*/
- if (old_blocks < new_blocks) {
- for (i = 0; i < rfs->new_fs->group_desc_count; i++) {
- if (!ext2fs_bg_has_super(rfs->new_fs, i)) {
- group_blk += rfs->new_fs->super->s_blocks_per_group;
- continue;
- }
- make_way_for_descriptors(rfs, i, group_blk);
- group_blk += rfs->new_fs->super->s_blocks_per_group;
- }
- }
- /*
- * Finally, if we're shrinking the filesystem, we need to
- * move all of the blocks that don't fit any more
- */
- for (blk = rfs->new_fs->super->s_blocks_count;
- blk < rfs->old_fs->super->s_blocks_count; blk++) {
- if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk))
- ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
+ for (i = 0; i < fs->group_desc_count; i++) {
+ if (!ext2fs_bg_has_super(fs, i))
+ goto next_group;
+ for (blk = group_blk;
+ blk < group_blk + 1 + new_blocks; blk++) {
+ ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
+ ext2fs_mark_block_bitmap(fs->block_map, blk);
+
+ /*
+ * 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)
+ fs->group_desc[i].bg_inode_bitmap = 0;
+
+ /*
+ * Check to see if we overlap with the inode
+ * table
+ */
+ if (blk < fs->group_desc[i].bg_inode_table)
+ continue;
+ if (blk >= (fs->group_desc[i].bg_inode_table +
+ fs->inode_blocks_per_group))
+ continue;
+ fs->group_desc[i].bg_inode_table = 0;
+ blk = fs->group_desc[i].bg_inode_table +
+ fs->inode_blocks_per_group - 1;
+ }
+ if (fs->group_desc[i].bg_inode_table &&
+ fs->group_desc[i].bg_inode_bitmap &&
+ fs->group_desc[i].bg_block_bitmap)
+ goto next_group;
+
+ /*
+ * Allocate the missing bitmap and inode table
+ * structures, passing in rfs->reserve_blocks to
+ * prevent a conflict.
+ */
+ if (fs->group_desc[i].bg_block_bitmap)
+ ext2fs_mark_block_bitmap(rfs->reserve_blocks,
+ fs->group_desc[i].bg_block_bitmap);
+ if (fs->group_desc[i].bg_inode_bitmap)
+ ext2fs_mark_block_bitmap(rfs->reserve_blocks,
+ fs->group_desc[i].bg_inode_bitmap);
+ if (fs->group_desc[i].bg_inode_table)
+ for (blk = 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);
+
+ retval = ext2fs_allocate_group_table(fs, i,
+ rfs->reserve_blocks);
+ if (retval)
+ return retval;
+
+ /*
+ * Now make sure these blocks are reserved in the new
+ * block bitmap
+ */
+ ext2fs_mark_block_bitmap(fs->block_map,
+ fs->group_desc[i].bg_block_bitmap);
+ ext2fs_mark_block_bitmap(fs->block_map,
+ fs->group_desc[i].bg_inode_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)
+ */
+ 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;
+ }
+
+ next_group:
+ group_blk += rfs->new_fs->super->s_blocks_per_group;
}
}
-
-
-
-
/*
* This is the top-level routine which does the dirty deed....
*/
@@ -249,28 +349,60 @@
ext2_resize_t rfs;
errcode_t retval;
+ retval = ext2fs_read_bitmaps(fs);
+ if (retval)
+ return retval;
+
/*
- * First, create the data structure
+ * Create the data structure
*/
rfs = malloc(sizeof(struct ext2_resize_struct));
if (!rfs)
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) {
- free(rfs);
- return retval;
- }
+ if (retval)
+ goto errout;
+
retval = adjust_superblock(rfs, new_size);
if (retval)
goto errout;
+
+ retval = determine_relocations(rfs);
+ if (retval)
+ goto errout;
+
+ printf("\nOld superblock:\n");
+ list_super(rfs->old_fs->super);
+ printf("\n\nNew superblock:\n");
+ list_super(rfs->new_fs->super);
+ printf("\n");
+
+ retval = ext2fs_move_blocks(rfs->old_fs, rfs->reserve_blocks,
+ EXT2_BMOVE_GET_DBLIST);
+
+ retval = ext2fs_close(rfs->new_fs);
+ if (retval)
+ return retval;
+
+ ext2fs_free(rfs->old_fs);
return 0;
errout:
- ext2fs_free(rfs->new_fs);
+ 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 1c90db1..5c1dad3 100644
--- a/resize/resize2fs.h
+++ b/resize/resize2fs.h
@@ -39,7 +39,13 @@
ext2_filsys old_fs;
ext2_filsys new_fs;
ext2_brel block_relocate;
- ext2fs_block_bitmap move_blocks;
+ 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;