Many files:

Checkin of work to date.  (Pretty much completely working now.)
bitmap-optimize
Theodore Ts'o 1997-06-17 03:52:12 +00:00
parent 05e112a11b
commit c762c8e632
13 changed files with 1457 additions and 369 deletions

View File

@ -12,21 +12,28 @@ INSTALL = @INSTALL@
@MCONFIG@
PROGS= resize2fs
TEST_PROGS= test_extent
MANPAGES= resize2fs.8
RESIZE_OBJS= inodemap.o resize2fs.o main.o
RESIZE_OBJS= extent.o ext2_block_move.o ext2_inode_move.o resize2fs.o \
main.o sim_progress.o
SRCS= $(srcdir)/inodemap.c \
TEST_EXTENT_OBJS= extent.o test_extent.o
SRCS= $(srcdir)/extent.c \
$(srcdir)/ext2_block_move.c \
$(srcdir)/ext2_inode_move.c \
$(srcdir)/resize2fs.c \
$(srcdir)/main.c
$(srcdir)/main.c \
$(srcdir)/sim_progress.c
LIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR) $(LIBUUID)
DEPLIBS= $(LIBEXT2FS) $(LIBE2P) $(LIBCOM_ERR) $(LIBUUID)
LIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
DEPLIBS= $(LIBEXT2FS) $(LIBCOM_ERR) $(LIBUUID)
.c.o:
$(CC) -c $(ALL_CFLAGS) $< -o $@
all:: $(PROGS) $(MANPAGES)
all:: $(PROGS) $(TEST_PROGS) $(MANPAGES)
resize2fs: $(RESIZE_OBJS) $(DEPLIBS)
$(CC) $(ALL_LDFLAGS) -o resize2fs $(RESIZE_OBJS) $(LIBS)
@ -35,6 +42,9 @@ resize2fs.8: $(SUBSTITUTE) $(srcdir)/resize2fs.8.in
-$(CHMOD) +x $(SUBSTITUTE)
$(SUBSTITUTE) $(srcdir)/resize2fs.8.in resize2fs.8
test_extent: $(TEST_EXTENT_OBJS)
$(CC) $(ALL_LDFLAGS) -o test_extent $(TEST_EXTENT_OBJS) $(LIBS)
installdirs:
$(top_srcdir)/mkinstalldirs $(DESTDIR)$(usbindir) \
$(DESTDIR)$(man8dir) $(DESTDIR)$(cat8dir)
@ -56,13 +66,52 @@ uninstall:
$(RM) -f $(man8dir)/$$i; \
done
test_extent.out: test_extent $(srcdir)/test_extent.in
./test_extent < $(srcdir)/test_extent.in > test_extent.out
check: test_extent.out
@if cmp -s test_extent.out $(srcdir)/test_extent.in ; then \
echo "Test succeeded." ; \
else \
echo "Test failed!" ; \
diff test_extent.out $(srcdir)/test_extent.in ; \
exit 1 ; \
fi
clean:
$(RM) -f $(PROGS) $(MANPAGES) \#* *.s *.o *.a *~ core
$(RM) -f $(PROGS) $(TEST_PROGS) $(MANPAGES) \#* *.s *.o *.a *~ core \
test_extent.out
mostlyclean: clean
distclean: clean
$(RM) -f .depend Makefile
#
# Kludge to create a "special" e2fsprogs distribution file.
#
SRCROOT = `echo e2fsprogs-@E2FSPROGS_VERSION@ | sed -e 's/-WIP//' \
-e 's/pre-//' -e 's/-PLUS//'`
TAR=tar
$(top_srcdir)/.exclude-file:
(cd $(top_srcdir)/.. ; find e2fsprogs \( -name \*~ -o -name \*.orig \
-o -name CVS -o -name \*.rej \) -print \
> .exclude-file)
echo "$(SRCROOT)/build" >> $(top_srcdir)/.exclude-file
echo "$(SRCROOT)/rpm.log" >> $(top_srcdir)/.exclude-file
echo "$(SRCROOT)/.exclude-file" >> $(top_srcdir)/.exclude-file
echo $(SRCROOT)/e2fsprogs-@E2FSPROGS_VERSION@.tar.gz \
>> $(top_srcdir)/.exclude-file
source_tar_file: $(top_srcdir)/.exclude-file
(cd $(top_srcdir)/..; a=$(SRCROOT); rm -f $$a ; ln -sf e2fsprogs $$a ; \
$(TAR) -c -h -v -f - \
-X $$a/.exclude-file $$a | \
gzip -9 > e2fsprogs-@E2FSPROGS_VERSION@.tar.gz)
rm -f $(top_srcdir)/.exclude-file
# +++ Dependency line eater +++
#
# Makefile dependencies follow. This must be the last section in

View File

@ -1,8 +1,2 @@
TODO
*) Inode table relocation
*) Inode relocation
*) Summary information collection

230
resize/ext2_block_move.c Normal file
View File

@ -0,0 +1,230 @@
/*
* ext2_block_move.c --- ext2resizer block mover
*
* Copyright (C) 1997 Theodore Ts'o
*
* %Begin-Header%
* All rights reserved.
* %End-Header%
*/
#include "resize2fs.h"
struct process_block_struct {
ino_t ino;
struct ext2_inode * inode;
ext2_extent bmap;
errcode_t error;
int is_dir;
int flags;
};
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;
blk_t block, new;
int ret = 0;
block = *block_nr;
new = ext2fs_extent_translate(pb->bmap, block);
if (new) {
*block_nr = new;
ret |= BLOCK_CHANGED;
if (pb->flags & RESIZE_DEBUG_BMOVE)
printf("ino=%ld, blockcnt=%d, %u->%u\n", pb->ino,
blockcnt, block, new);
}
if (pb->is_dir) {
retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
*block_nr, blockcnt);
if (retval) {
pb->error = retval;
ret |= BLOCK_ABORT;
}
}
return ret;
}
errcode_t ext2fs_block_move(ext2_resize_t rfs)
{
ext2_extent bmap;
blk_t blk, old, new;
ext2_filsys fs = rfs->new_fs;
ext2_filsys old_fs = rfs->old_fs;
ino_t ino;
struct ext2_inode inode;
errcode_t retval;
struct process_block_struct pb;
ext2_inode_scan scan = 0;
char *block_buf;
int size, c;
int to_move, moved;
ext2_sim_progmeter progress = 0;
new = fs->super->s_first_data_block;
if (!rfs->itable_buf) {
rfs->itable_buf = malloc(fs->blocksize *
fs->inode_blocks_per_group);
if (!rfs->itable_buf)
return ENOMEM;
}
retval = ext2fs_create_extent_table(&bmap, 0);
if (retval)
return retval;
/*
* The first step is to figure out where all of the blocks
* will go.
*/
to_move = moved = 0;
for (blk = old_fs->super->s_first_data_block;
blk < old_fs->super->s_blocks_count; blk++) {
if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
continue;
if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
continue;
while (1) {
if (new >= fs->super->s_blocks_count) {
retval = ENOSPC;
goto errout;
}
if (!ext2fs_test_block_bitmap(fs->block_map, new) &&
!ext2fs_test_block_bitmap(rfs->reserve_blocks,
new))
break;
new++;
}
ext2fs_mark_block_bitmap(fs->block_map, new);
ext2fs_add_extent_entry(bmap, blk, new);
to_move++;
}
if (to_move == 0)
return 0;
/*
* Step two is to actually move the blocks
*/
retval = ext2fs_iterate_extent(bmap, 0, 0, 0);
if (retval) goto errout;
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
retval = ext2fs_progress_init(&progress,
"Relocating blocks", 30, 40, to_move, 0);
if (retval)
return retval;
}
while (1) {
retval = ext2fs_iterate_extent(bmap, &old, &new, &size);
if (retval) goto errout;
if (!size)
break;
if (rfs->flags & RESIZE_DEBUG_BMOVE)
printf("Moving %d blocks %u->%u\n", size,
old, new);
do {
c = size;
if (c > fs->inode_blocks_per_group)
c = fs->inode_blocks_per_group;
retval = io_channel_read_blk(fs->io, old, c,
rfs->itable_buf);
if (retval) goto errout;
retval = io_channel_write_blk(fs->io, new, c,
rfs->itable_buf);
if (retval) goto errout;
size -= c;
new += c;
old += c;
moved += c;
io_channel_flush(fs->io);
if (progress)
ext2fs_progress_update(progress, moved);
} while (size > 0);
io_channel_flush(fs->io);
}
if (progress) {
ext2fs_progress_close(progress);
progress = 0;
}
/*
* Step 3 is where we update the block pointers
*/
retval = ext2fs_open_inode_scan(old_fs, 0, &scan);
if (retval) goto errout;
pb.error = 0;
pb.bmap = bmap;
pb.flags = rfs->flags;
block_buf = malloc(old_fs->blocksize * 3);
if (!block_buf) {
retval = ENOMEM;
goto errout;
}
/*
* We're going to initialize the dblist while we're at it.
*/
if (old_fs->dblist) {
ext2fs_free_dblist(old_fs->dblist);
old_fs->dblist = NULL;
}
retval = ext2fs_init_dblist(old_fs, 0);
if (retval)
return retval;
retval = ext2fs_get_next_inode(scan, &ino, &inode);
if (retval) goto errout;
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
retval = ext2fs_progress_init(&progress,
"Updating block references", 30, 40,
old_fs->super->s_inodes_count, 0);
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.is_dir = LINUX_S_ISDIR(inode.i_mode);
retval = ext2fs_block_iterate2(old_fs, ino, 0, block_buf,
process_block, &pb);
if (retval)
goto errout;
if (pb.error) {
retval = pb.error;
goto errout;
}
next:
if (progress)
ext2fs_progress_update(progress, ino);
retval = ext2fs_get_next_inode(scan, &ino, &inode);
if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
goto next;
}
retval = 0;
errout:
if (progress)
ext2fs_progress_close(progress);
ext2fs_free_extent_table(bmap);
if (scan)
ext2fs_close_inode_scan(scan);
return retval;
}

300
resize/ext2_inode_move.c Normal file
View File

@ -0,0 +1,300 @@
/*
* ext2_inode_move.c --- ext2resizer inode mover
*
* Copyright (C) 1997 Theodore Ts'o
*
* %Begin-Header%
* All rights reserved.
* %End-Header%
*/
#include "resize2fs.h"
/*
* Progress callback
*/
struct callback_info {
ext2_sim_progmeter progress;
int offset;
};
static errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan,
dgrp_t group, void * private)
{
struct callback_info *cb = private;
if (!cb->progress)
return 0;
ext2fs_progress_update(cb->progress, group - cb->offset + 1);
return 0;
}
struct istruct {
ext2_sim_progmeter progress;
ext2_extent imap;
int flags;
int num;
};
static int check_and_change_inodes(ino_t dir, int entry,
struct ext2_dir_entry *dirent, int offset,
int blocksize, char *buf, void *private)
{
struct istruct *is = private;
ino_t new;
if (is->progress && offset == 0) {
ext2fs_progress_update(is->progress, ++is->num);
}
if (!dirent->inode)
return 0;
new = ext2fs_extent_translate(is->imap, dirent->inode);
if (!new)
return 0;
if (is->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode translate (dir=%ld, name=%.*s, %u->%ld)\n",
dir, dirent->name_len, dirent->name,
dirent->inode, new);
dirent->inode = new;
return DIRENT_CHANGED;
}
/*
* Function to obtain the dblist information (if we didn't get it
* earlier)
*/
struct process_block_struct {
ino_t ino;
struct ext2_inode * inode;
errcode_t error;
};
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 = 0;
retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
*block_nr, blockcnt);
if (retval) {
pb->error = retval;
ret |= BLOCK_ABORT;
}
return ret;
}
static errcode_t get_dblist(ext2_filsys fs, int flags)
{
ext2_inode_scan scan = 0;
errcode_t retval;
char *block_buf;
struct process_block_struct pb;
ext2_sim_progmeter progress = 0;
ino_t ino;
struct ext2_inode inode;
retval = ext2fs_open_inode_scan(fs, 0, &scan);
if (retval) goto errout;
pb.error = 0;
block_buf = malloc(fs->blocksize * 3);
if (!block_buf) {
retval = ENOMEM;
goto errout;
}
/*
* We're going to initialize the dblist while we're at it.
*/
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) goto errout;
if (flags & RESIZE_PERCENT_COMPLETE) {
retval = ext2fs_progress_init(&progress,
"Finding directories", 30, 40,
fs->super->s_inodes_count, 0);
if (retval)
return retval;
}
while (ino) {
if ((inode.i_links_count == 0) ||
!ext2fs_inode_has_valid_blocks(&inode) ||
!LINUX_S_ISDIR(inode.i_mode))
goto next;
pb.ino = ino;
pb.inode = &inode;
retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
process_block, &pb);
if (retval)
goto errout;
if (pb.error) {
retval = pb.error;
goto errout;
}
next:
if (progress)
ext2fs_progress_update(progress, ino);
retval = ext2fs_get_next_inode(scan, &ino, &inode);
if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
goto next;
}
retval = 0;
errout:
if (progress)
ext2fs_progress_close(progress);
if (scan)
ext2fs_close_inode_scan(scan);
return retval;
}
errcode_t ext2fs_inode_move(ext2_resize_t rfs)
{
ino_t ino, new;
struct ext2_inode inode;
ext2_inode_scan scan = NULL;
ext2_extent imap;
errcode_t retval;
int group;
struct istruct is;
struct callback_info callback_info;
ext2_sim_progmeter progress = 0;
if (rfs->old_fs->group_desc_count <=
rfs->new_fs->group_desc_count)
return 0;
retval = ext2fs_create_extent_table(&imap, 0);
if (retval)
return retval;
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
if (retval) goto errout;
retval = ext2fs_inode_scan_goto_blockgroup(scan,
rfs->new_fs->group_desc_count);
if (retval) goto errout;
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
callback_info.offset = rfs->new_fs->group_desc_count;
group = (rfs->old_fs->group_desc_count -
rfs->new_fs->group_desc_count);
retval = ext2fs_progress_init(&progress,
"Moving inodes", 30, 40, group, 0);
if (retval)
return retval;
ext2fs_set_inode_callback(scan, progress_callback,
&callback_info);
}
callback_info.progress = progress;
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) goto errout;
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) {
retval = ENOSPC;
goto errout;
}
}
ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new);
retval = ext2fs_write_inode(rfs->old_fs, new, &inode);
if (retval) goto errout;
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++;
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode moved %ld->%ld\n", ino, new);
ext2fs_add_extent_entry(imap, ino, new);
}
io_channel_flush(rfs->new_fs->io);
if (progress) {
ext2fs_progress_close(progress);
progress = 0;
}
/*
* Get the list of directory blocks, if necessary
*/
if (!rfs->old_fs->dblist) {
retval = get_dblist(rfs->old_fs, rfs->flags);
if (retval) goto errout;
}
/*
* Now, we iterate over all of the directories to update the
* inode references
*/
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
retval = ext2fs_progress_init(&progress,
"Updating inode references", 30, 40,
ext2fs_dblist_count(rfs->old_fs->dblist), 0);
if (retval)
return retval;
}
is.imap = imap;
is.flags = rfs->flags;
is.num = 0;
is.progress = progress;
retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
DIRENT_FLAG_INCLUDE_EMPTY, 0,
check_and_change_inodes, &is);
/* if (retval) goto errout; */
errout:
if (progress)
ext2fs_progress_close(progress);
ext2fs_free_extent_table(imap);
if (scan)
ext2fs_close_inode_scan(scan);
return retval;
}

224
resize/extent.c Normal file
View File

@ -0,0 +1,224 @@
/*
* extent.c --- ext2 extent abstraction
*
* This abstraction is used to provide a compact way of representing a
* translation table, for moving multiple contiguous ranges (extents)
* of blocks or inodes.
*
* Copyright (C) 1997 Theodore Ts'o
*
* %Begin-Header%
* All rights reserved.
* %End-Header%
*/
#include "resize2fs.h"
struct ext2_extent_entry {
__u32 old, new;
int size;
};
struct _ext2_extent {
struct ext2_extent_entry *list;
int cursor;
int size;
int num;
int sorted;
};
/*
* Create an extent table
*/
errcode_t ext2fs_create_extent_table(ext2_extent *ret_extent, int size)
{
ext2_extent new;
new = malloc(sizeof(struct _ext2_extent));
if (!new)
return ENOMEM;
memset(new, 0, sizeof(struct _ext2_extent));
new->size = size ? size : 50;
new->cursor = 0;
new->num = 0;
new->sorted = 1;
new->list = malloc(sizeof(struct ext2_extent_entry) * new->size);
if (!new->list) {
free(new);
return ENOMEM;
}
memset(new->list, 0, sizeof(struct ext2_extent_entry) * new->size);
*ret_extent = new;
return 0;
}
/*
* Free an extent table
*/
void ext2fs_free_extent_table(ext2_extent extent)
{
if (extent->list)
free(extent->list);
extent->list = 0;
extent->size = 0;
extent->num = 0;
free(extent);
}
/*
* Add an entry to the extent table
*/
errcode_t ext2fs_add_extent_entry(ext2_extent extent, __u32 old, __u32 new)
{
struct ext2_extent_entry *p;
int newsize;
int curr;
struct ext2_extent_entry *ent;
if (extent->num >= extent->size) {
newsize = extent->size + 100;
p = realloc(extent->list,
sizeof(struct ext2_extent_entry) * newsize);
if (!p)
return ENOMEM;
extent->list = p;
extent->size = newsize;
}
curr = extent->num;
ent = extent->list + curr;
if (curr) {
/*
* Check to see if this can be coalesced with the last
* extent
*/
ent--;
if ((ent->old + ent->size == old) &&
(ent->new + ent->size == new)) {
ent->size++;
return 0;
}
/*
* Now see if we're going to ruin the sorting
*/
if (ent->old + ent->size > old)
extent->sorted = 0;
ent++;
}
ent->old = old;
ent->new = new;
ent->size = 1;
extent->num++;
return 0;
}
/*
* Helper function for qsort
*/
static int extent_cmp(const void *a, const void *b)
{
const struct ext2_extent_entry *db_a = a;
const struct ext2_extent_entry *db_b = 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
*/
__u32 ext2fs_extent_translate(ext2_extent extent, __u32 old)
{
int low, high, mid;
ino_t lowval, highval;
float range;
if (!extent->sorted) {
qsort(extent->list, extent->num,
sizeof(struct ext2_extent_entry), extent_cmp);
extent->sorted = 1;
}
low = 0;
high = extent->num-1;
while (low <= high) {
#if 0
mid = (low+high)/2;
#else
if (low == high)
mid = low;
else {
/* Interpolate for efficiency */
lowval = extent->list[low].old;
highval = extent->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 >= extent->list[mid].old) &&
(old < extent->list[mid].old + extent->list[mid].size))
return (extent->list[mid].new +
(old - extent->list[mid].old));
if (old < extent->list[mid].old)
high = mid-1;
else
low = mid+1;
}
return 0;
}
/*
* For debugging only
*/
void ext2fs_extent_dump(ext2_extent extent, FILE *out)
{
int i;
struct ext2_extent_entry *ent;
fputs("# Extent dump:\n", out);
fprintf(out, "#\tNum=%d, Size=%d, Cursor=%d, Sorted=%d\n",
extent->num, extent->size, extent->cursor, extent->sorted);
for (i=0, ent=extent->list; i < extent->num; i++, ent++) {
fprintf(out, "#\t\t %u -> %u (%d)\n", ent->old,
ent->new, ent->size);
}
}
/*
* Iterate over the contents of the extent table
*/
errcode_t ext2fs_iterate_extent(ext2_extent extent, __u32 *old,
__u32 *new, int *size)
{
struct ext2_extent_entry *ent;
if (!old) {
extent->cursor = 0;
return 0;
}
if (extent->cursor >= extent->num) {
*old = 0;
*new = 0;
*size = 0;
return 0;
}
ent = extent->list + extent->cursor++;
*old = ent->old;
*new = ent->new;
*size = ent->size;
return 0;
}

View File

@ -1,250 +0,0 @@
/*
* 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;
}
struct istruct {
inode_map imap;
int flags;
};
int check_and_change_inodes(ino_t dir, int entry,
struct ext2_dir_entry *dirent, int offset,
int blocksize, char *buf, void *private)
{
struct istruct *is = private;
ino_t new;
if (!dirent->inode)
return 0;
new = inode_map_translate(is->imap, dirent->inode);
if (!new)
return 0;
if (is->flags & RESIZE_DEBUG_INODEMAP)
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;
struct istruct is;
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++;
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
printf("Inode moved %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
*/
is.imap = imap;
is.flags = rfs->flags;
retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist, 0, 0,
check_and_change_inodes, &is);
if (retval)
return retval;
return 0;
}

View File

@ -8,6 +8,13 @@
* %End-Header%
*/
#ifdef HAVE_GETOPT_H
#include <getopt.h>
#endif
#include <fcntl.h>
#include <sys/ioctl.h>
#include "resize2fs.h"
#define E2FSPROGS_VERSION "1.10"
@ -15,9 +22,9 @@
char *program_name, *device_name;
static volatile void usage (char *program_name)
static volatile void usage (char *prog)
{
fprintf (stderr, "usage: %s device new-size\n", program_name);
fprintf (stderr, "usage: %s [-d debug_flags] [-p] [-F] device new-size\n", prog);
exit (1);
}
@ -27,6 +34,8 @@ void main (int argc, char ** argv)
ext2_filsys fs;
int c;
int flags = 0;
int flush = 0;
int fd;
blk_t new_size;
io_manager io_ptr;
@ -36,11 +45,14 @@ void main (int argc, char ** argv)
if (argc && *argv)
program_name = *argv;
while ((c = getopt (argc, argv, "d:hp")) != EOF) {
while ((c = getopt (argc, argv, "d:Fhp")) != EOF) {
switch (c) {
case 'h':
usage(program_name);
break;
case 'F':
flush = 1;
break;
case 'd':
flags |= atoi(optarg);
break;
@ -57,6 +69,27 @@ void main (int argc, char ** argv)
new_size = atoi(argv[optind++]);
initialize_ext2_error_table();
if (flush) {
#ifdef BLKFLSBUF
fd = open(device_name, O_RDONLY, 0);
if (fd < 0) {
com_err("open", errno, "while opening %s for flushing",
device_name);
exit(1);
}
if (ioctl(fd, BLKFLSBUF, 0) < 0) {
com_err("BLKFLSBUF", errno, "while trying to flush %s",
device_name);
exit(1);
}
close(fd);
#else
fprintf(stderr, "BLKFLSBUF not supported");
exit(1);
#endif /* BLKFLSBUF */
}
if (flags & RESIZE_DEBUG_IO) {
io_ptr = test_io_manager;
test_io_backing_manager = unix_io_manager;

View File

@ -7,23 +7,56 @@ resize2fs \- ext2 file system resizer
.SH SYNOPSIS
.B resize2fs
[
device
.B \-d
.I debug-flags
]
[
.B \-p
]
[
.B \-F
]
.I device
.I size
.SH DESCRIPTION
The
.B resize2fs
.B resize2fs
program will resize ext2 file systems. It can be used to enlarge or
shrink an ext2 file system.
.br
shrink an ext2 file system so that it will have
.I size
blocks.
The device containing the ext2 filesystem is specified by the
.I device
is the special file corresponding to the device containing the ext2
file system (e.g /dev/hdXX).
parameter.
.SH OPTIONS
.TP
.I -h
Displays a help message.
.I \-d debug-flags
Turns on various resize2fs debugging features.
.I debug-flags
should be computed by adding the numbers of the desired features
from the following list:
.br
\ 1\ \-\ Print out all disk I/O
.br
\ 2\ \-\ Debug block relocations
.br
\ 8\ \-\ Debug inode relocations
.br
\ 16\ \-\ Debug moving the inode table
.TP
.I \-p
Prints out a percentage completion bars for each
.B resize2fs
operation, so that the user can keep track of what
the program is doing.
.TP
.I \-F
Flush the filesystem device's buffer caches before beginning. Only
really useful for doing
.B resize2fs
time trials.
.SH AUTHOR
.B debugfs
.B resize2fs
was written by Theodore Ts'o <tytso@mit.edu>.
.SH SEE ALSO
.BR dumpe2fs (8),

View File

@ -29,13 +29,14 @@ static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
{
ext2_filsys fs;
int overhead = 0;
int rem;
int rem, adj = 0;
errcode_t retval;
ino_t real_end;
blk_t blk, group_block;
unsigned long i, j;
struct ext2_group_desc *new;
int old_numblocks, numblocks, adjblocks;
ext2_sim_progmeter progress = 0;
fs = rfs->new_fs;
fs->super->s_blocks_count = new_size;
@ -95,14 +96,21 @@ retry:
fs->super->s_free_blocks_count +=
(fs->super->s_blocks_count - blk);
/*
* Adjust the number of reserved blocks
*/
blk = rfs->old_fs->super->s_r_blocks_count * 100 /
rfs->old_fs->super->s_blocks_count;
fs->super->s_r_blocks_count = ((fs->super->s_blocks_count * blk)
/ 100);
/*
* Adjust the bitmaps for size
*/
retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
fs->super->s_inodes_count,
fs->inode_map);
if (retval)
return retval;
if (retval) goto errout;
real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
* fs->group_desc_count)) - 1 +
@ -110,8 +118,7 @@ retry:
retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
real_end, fs->block_map);
if (retval)
return retval;
if (retval) goto errout;
/*
* Reallocate the group descriptors as necessary.
@ -127,8 +134,10 @@ retry:
/*
* Fix the count of the last (old) block group
*/
if (rfs->old_fs->group_desc_count > fs->group_desc_count)
return 0;
if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
retval = 0;
goto errout;
}
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;
@ -148,14 +157,26 @@ retry:
/*
* Initialize the new block group descriptors
*/
if (rfs->old_fs->group_desc_count >= fs->group_desc_count)
return 0;
if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
retval = 0;
goto errout;
}
rfs->itable_buf = malloc(fs->blocksize * fs->inode_blocks_per_group);
if (!rfs->itable_buf)
return ENOMEM;
if (!rfs->itable_buf) {
retval = ENOMEM;
goto errout;
}
memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
group_block = fs->super->s_first_data_block +
rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
adj = rfs->old_fs->group_desc_count;
retval = ext2fs_progress_init(&progress,
"Initializing inode table", 30, 40,
fs->group_desc_count - adj, 0);
if (retval) goto errout;
}
for (i = rfs->old_fs->group_desc_count;
i < fs->group_desc_count; i++) {
memset(&fs->group_desc[i], 0,
@ -189,8 +210,7 @@ retry:
fs->group_desc[i].bg_used_dirs_count = 0;
retval = ext2fs_allocate_group_table(fs, i, 0);
if (retval)
return retval;
if (retval) goto errout;
/*
* Write out the new inode table
@ -199,54 +219,155 @@ retry:
fs->group_desc[i].bg_inode_table,
fs->inode_blocks_per_group,
rfs->itable_buf);
if (retval)
return retval;
if (retval) goto errout;
/* io_channel_flush(fs->io); */
if (progress)
ext2fs_progress_update(progress, i - adj + 1);
group_block += fs->super->s_blocks_per_group;
}
io_channel_flush(fs->io);
retval = 0;
errout:
if (progress)
ext2fs_progress_close(progress);
return retval;
}
/*
* This helper function creates a block bitmap with all of the
* filesystem meta-data blocks.
*/
static errcode_t mark_table_blocks(ext2_filsys fs,
ext2fs_block_bitmap *ret_bmap)
{
blk_t block, b;
int i,j;
ext2fs_block_bitmap bmap;
errcode_t retval;
retval = ext2fs_allocate_block_bitmap(fs, "meta-data blocks", &bmap);
if (retval)
return retval;
block = fs->super->s_first_data_block;
for (i = 0; i < fs->group_desc_count; i++) {
if (ext2fs_bg_has_super(fs, i)) {
/*
* Mark this group's copy of the superblock
*/
ext2fs_mark_block_bitmap(bmap, block);
/*
* Mark this group's copy of the descriptors
*/
for (j = 0; j < fs->desc_blocks; j++)
ext2fs_mark_block_bitmap(bmap, block + j + 1);
}
/*
* Mark the blocks used for the inode table
*/
for (j = 0, b = fs->group_desc[i].bg_inode_table;
j < fs->inode_blocks_per_group;
j++, b++)
ext2fs_mark_block_bitmap(bmap, b);
/*
* Mark block used for the block bitmap
*/
ext2fs_mark_block_bitmap(bmap,
fs->group_desc[i].bg_block_bitmap);
/*
* Mark block used for the inode bitmap
*/
ext2fs_mark_block_bitmap(bmap,
fs->group_desc[i].bg_inode_bitmap);
block += fs->super->s_blocks_per_group;
}
*ret_bmap = bmap;
return 0;
}
/*
* Some helper CPP macros
*/
#define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
#define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
#define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
#define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
#define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
#define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
((blk) < (FS_INODE_TB((fs), (i)) + \
(fs)->inode_blocks_per_group)))
/*
* 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)
static errcode_t blocks_to_move(ext2_resize_t rfs)
{
int i, j, max, adj;
int i, j, max;
blk_t blk, group_blk;
unsigned long old_blocks, new_blocks;
errcode_t retval;
ext2_filsys fs = rfs->new_fs;
ext2_filsys fs, old_fs;
ext2fs_block_bitmap meta_bmap;
retval = ext2fs_allocate_block_bitmap(rfs->old_fs,
"blocks to be moved",
fs = rfs->new_fs;
old_fs = rfs->old_fs;
if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
fs = rfs->old_fs;
retval = ext2fs_allocate_block_bitmap(fs, "reserved blocks",
&rfs->reserve_blocks);
if (retval)
return retval;
retval = ext2fs_allocate_block_bitmap(fs, "blocks to be moved",
&rfs->move_blocks);
if (retval)
return retval;
retval = mark_table_blocks(fs, &meta_bmap);
if (retval)
return retval;
fs = rfs->new_fs;
/*
* 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))
blk < old_fs->super->s_blocks_count; blk++) {
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
!ext2fs_test_block_bitmap(meta_bmap, blk)) {
ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
rfs->needed_blocks++;
}
ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
}
old_blocks = rfs->old_fs->desc_blocks;
old_blocks = old_fs->desc_blocks;
new_blocks = fs->desc_blocks;
if (old_blocks == new_blocks)
return 0;
if (old_blocks == new_blocks) {
retval = 0;
goto errout;
}
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 (max > old_fs->group_desc_count)
max = old_fs->group_desc_count;
group_blk = old_fs->super->s_first_data_block;
/*
* If we're reducing the number of descriptor blocks, this
* makes life easy. :-) We just have to mark some extra
@ -258,15 +379,16 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
group_blk += fs->super->s_blocks_per_group;
continue;
}
for (blk = group_blk+1+old_blocks;
blk < group_blk+1+new_blocks; blk++) {
for (blk = group_blk+1+new_blocks;
blk < group_blk+1+old_blocks; blk++) {
ext2fs_unmark_block_bitmap(fs->block_map,
blk);
rfs->needed_blocks--;
}
group_blk += fs->super->s_blocks_per_group;
}
return 0;
retval = 0;
goto errout;
}
/*
* If we're increasing the number of descriptor blocks, life
@ -283,28 +405,26 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
/*
* Check to see if we overlap with the inode
* or block bitmap
* or block bitmap, or the inode tables. If
* not, and the block is in use, then mark it
* as a block to be moved.
*/
if (blk == fs->group_desc[i].bg_block_bitmap) {
fs->group_desc[i].bg_block_bitmap = 0;
if (IS_BLOCK_BM(fs, i, blk)) {
FS_BLOCK_BM(fs, i) = 0;
rfs->needed_blocks++;
} else if (IS_INODE_BM(fs, i, blk)) {
FS_INODE_BM(fs, i) = 0;
rfs->needed_blocks++;
} else if (IS_INODE_TB(fs, i, blk)) {
FS_INODE_TB(fs, i) = 0;
rfs->needed_blocks++;
} else if (ext2fs_test_block_bitmap(old_fs->block_map,
blk) &&
!ext2fs_test_block_bitmap(meta_bmap, blk)) {
ext2fs_mark_block_bitmap(rfs->move_blocks,
blk);
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
*/
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;
blk = fs->group_desc[i].bg_inode_table +
fs->inode_blocks_per_group - 1;
fs->group_desc[i].bg_inode_table = 0;
}
if (fs->group_desc[i].bg_inode_table &&
fs->group_desc[i].bg_inode_bitmap &&
@ -312,9 +432,8 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
goto next_group;
/*
* Allocate the missing bitmap and inode table
* structures, passing in rfs->reserve_blocks to
* prevent a conflict.
* Reserve the existing meta blocks that we know
* aren't to be moved.
*/
if (fs->group_desc[i].bg_block_bitmap)
ext2fs_mark_block_bitmap(rfs->reserve_blocks,
@ -328,19 +447,34 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
ext2fs_mark_block_bitmap(rfs->reserve_blocks,
blk);
/*
* Allocate the missing data structures
*/
retval = ext2fs_allocate_group_table(fs, i,
rfs->reserve_blocks);
if (retval)
return retval;
goto errout;
/*
* Now make sure these blocks are reserved in the new
* block bitmap
* For those structures that have changed, we need to
* do bookkeepping.
*/
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);
if (FS_BLOCK_BM(old_fs, i) !=
(blk = FS_BLOCK_BM(fs, i))) {
ext2fs_mark_block_bitmap(fs->block_map, blk);
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
!ext2fs_test_block_bitmap(meta_bmap, blk))
ext2fs_mark_block_bitmap(rfs->move_blocks,
blk);
}
if (FS_INODE_BM(old_fs, i) !=
(blk = FS_INODE_BM(fs, i))) {
ext2fs_mark_block_bitmap(fs->block_map, blk);
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
!ext2fs_test_block_bitmap(meta_bmap, blk))
ext2fs_mark_block_bitmap(rfs->move_blocks,
blk);
}
/*
* The inode table, if we need to relocate it, is
@ -349,29 +483,25 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
* 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)
if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
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;
rfs->needed_blocks += fs->inode_blocks_per_group;
/*
* Mark the new inode table as in use in the new block
* allocation bitmap.
* allocation bitmap, and move any blocks that might
* be necessary.
*/
for (blk = fs->group_desc[i].bg_inode_table, j=0;
j < fs->inode_blocks_per_group ; j++, blk++)
j < fs->inode_blocks_per_group ; j++, blk++) {
ext2fs_mark_block_bitmap(fs->block_map, blk);
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
!ext2fs_test_block_bitmap(meta_bmap, blk))
ext2fs_mark_block_bitmap(rfs->move_blocks,
blk);
}
/*
* Make sure the old inode table is reserved in the
* block reservation bitmap.
@ -383,7 +513,13 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
next_group:
group_blk += rfs->new_fs->super->s_blocks_per_group;
}
return 0;
retval = 0;
errout:
if (meta_bmap)
ext2fs_free_block_bitmap(meta_bmap);
return retval;
}
@ -393,13 +529,15 @@ static errcode_t determine_relocations(ext2_resize_t rfs)
* 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)
static errcode_t move_itables(ext2_resize_t rfs)
{
int i, n, num, max, size, diff;
ext2_filsys fs = rfs->new_fs;
char *cp;
blk_t old, new;
errcode_t retval, err;
ext2_sim_progmeter progress = 0;
int to_move, moved;
max = fs->group_desc_count;
if (max > rfs->old_fs->group_desc_count)
@ -411,6 +549,25 @@ errcode_t move_itables(ext2_resize_t rfs)
if (!rfs->itable_buf)
return ENOMEM;
}
/*
* Figure out how many inode tables we need to move
*/
to_move = moved = 0;
for (i=0; i < max; i++)
if (rfs->old_fs->group_desc[i].bg_inode_table !=
fs->group_desc[i].bg_inode_table)
to_move++;
if (to_move == 0)
return 0;
if (rfs->flags & RESIZE_PERCENT_COMPLETE) {
retval = ext2fs_progress_init(&progress,
"Moving inode table", 30, 40, to_move, 0);
if (retval)
return retval;
}
for (i=0; i < max; i++) {
old = rfs->old_fs->group_desc[i].bg_inode_table;
@ -419,7 +576,7 @@ errcode_t move_itables(ext2_resize_t rfs)
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
printf("Itable move group %d block "
"%ld->%ld (diff %d)\n",
"%u->%u (diff %d)\n",
i, old, new, diff);
if (!diff)
@ -458,20 +615,27 @@ errcode_t move_itables(ext2_resize_t rfs)
diff, rfs->itable_buf - fs->blocksize * diff);
if (retval)
goto backout;
}
}
io_channel_flush(fs->io);
if (progress)
ext2fs_progress_update(progress, ++moved);
}
ext2fs_flush(rfs->new_fs);
io_channel_flush(fs->io);
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
printf("Inode table move finished.\n");
if (progress)
ext2fs_progress_close(progress);
return 0;
backout:
if (progress)
ext2fs_progress_close(progress);
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
printf("Error: %s; now backing out!\n", error_message(retval));
while (--i >= 0) {
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
printf("Group %d block %ld->%ld\n", i, new, old);
printf("Group %d block %u->%u\n", i, new, old);
old = rfs->old_fs->group_desc[i].bg_inode_table;
new = fs->group_desc[i].bg_inode_table;
@ -554,7 +718,6 @@ errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags)
{
ext2_resize_t rfs;
errcode_t retval;
int bmove_flags;
retval = ext2fs_read_bitmaps(fs);
if (retval)
@ -579,24 +742,17 @@ errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags)
if (retval)
goto errout;
retval = determine_relocations(rfs);
retval = blocks_to_move(rfs);
if (retval)
goto errout;
if (rfs->flags & RESIZE_DEBUG_BMOVE)
printf("Number of free blocks: %d, Needed: %d\n",
fs->super->s_free_blocks_count, rfs->needed_blocks);
printf("Number of free blocks: %d/%d, Needed: %d\n",
rfs->old_fs->super->s_free_blocks_count,
rfs->new_fs->super->s_free_blocks_count,
rfs->needed_blocks);
if (rfs->needed_blocks > fs->super->s_free_blocks_count) {
retval = ENOSPC;
goto errout;
}
bmove_flags = EXT2_BMOVE_GET_DBLIST;
if (rfs->flags & RESIZE_DEBUG_BMOVE)
bmove_flags |= EXT2_BMOVE_DEBUG;
retval = ext2fs_move_blocks(rfs->old_fs, rfs->reserve_blocks,
rfs->new_fs->block_map, bmove_flags);
retval = ext2fs_block_move(rfs);
if (retval)
goto errout;

View File

@ -31,6 +31,16 @@
#define const
#endif
/*
* For the extent map
*/
typedef struct _ext2_extent *ext2_extent;
/*
* For the simple progress meter
*/
typedef struct ext2_sim_progress *ext2_sim_progmeter;
/*
* Flags for the resizer; most are debugging flags only
*/
@ -40,6 +50,7 @@
#define RESIZE_DEBUG_ITABLEMOVE 0x0008
#define RESIZE_PERCENT_COMPLETE 0x0100
#define RESIZE_VERBOSE 0x0200
/*
* The core state structure for the ext2 resizer
@ -50,6 +61,7 @@ struct ext2_resize_struct {
ext2_filsys new_fs;
ext2_brel block_relocate;
ext2fs_block_bitmap reserve_blocks;
ext2fs_block_bitmap move_blocks;
int needed_blocks;
int flags;
char *itable_buf;
@ -59,3 +71,27 @@ typedef struct ext2_resize_struct *ext2_resize_t;
/* prototypes */
extern errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags);
extern errcode_t ext2fs_inode_move(ext2_resize_t rfs);
extern errcode_t ext2fs_block_move(ext2_resize_t rfs);
/* extent.c */
extern errcode_t ext2fs_create_extent_table(ext2_extent *ret_extent,
int size);
extern void ext2fs_free_extent_table(ext2_extent extent);
extern errcode_t ext2fs_add_extent_entry(ext2_extent extent,
__u32 old, __u32 new);
extern __u32 ext2fs_extent_translate(ext2_extent extent, __u32 old);
extern void ext2fs_extent_dump(ext2_extent extent, FILE *out);
extern errcode_t ext2fs_iterate_extent(ext2_extent extent, __u32 *old,
__u32 *new, int *size);
/* sim_progress.c */
extern errcode_t ext2fs_progress_init(ext2_sim_progmeter *ret_prog,
const char *label,
int labelwidth, int barwidth,
__u32 maxdone, int flags);
extern void ext2fs_progress_update(ext2_sim_progmeter prog,
__u32 current);
extern void ext2fs_progress_close(ext2_sim_progmeter prog);

106
resize/sim_progress.c Normal file
View File

@ -0,0 +1,106 @@
/*
* sim_progress.c --- simple progress meter
*/
#include "resize2fs.h"
struct ext2_sim_progress {
FILE *f;
char *label;
int labelwidth;
int barwidth;
__u32 maxdone;
__u32 current;
int shown;
int flags;
};
static errcode_t ext2fs_progress_display(ext2_sim_progmeter prog)
{
int i, width;
fputs(prog->label, prog->f);
width = prog->labelwidth - strlen(prog->label);
while (width-- > 0)
putc(' ', prog->f);
if (prog->labelwidth + prog->barwidth > 80) {
fputs("\n", prog->f);
for (width = prog->labelwidth; width > 0; width--)
putc(' ', prog->f);
}
for (i=0; i < prog->barwidth; i++)
putc('-', prog->f);
for (i=0; i < prog->barwidth; i++)
putc('\b', prog->f);
fflush(prog->f);
return 0;
}
void ext2fs_progress_update(ext2_sim_progmeter prog, __u32 current)
{
int old_level, level, num, i;
level = prog->barwidth * current / prog->maxdone;
old_level = prog->barwidth * prog->current / prog->maxdone;
prog->current = current;
num = level - old_level;
if (num == 0)
return;
if (num > 0) {
for (i=0; i < num; i++)
putc('X', prog->f);
} else {
num = -num;
for (i=0; i < num; i++)
putc('\b', prog->f);
for (i=0; i < num; i++)
putc('-', prog->f);
for (i=0; i < num; i++)
putc('\b', prog->f);
}
fflush(prog->f);
}
errcode_t ext2fs_progress_init(ext2_sim_progmeter *ret_prog,
const char *label,
int labelwidth, int barwidth,
__u32 maxdone, int flags)
{
ext2_sim_progmeter prog;
prog = malloc(sizeof(struct ext2_sim_progress));
if (!prog)
return ENOMEM;
memset(prog, 0, sizeof(struct ext2_sim_progress));
prog->label = malloc(strlen(label)+1);
if (!prog->label) {
free(prog);
return ENOMEM;
}
strcpy(prog->label, label);
prog->labelwidth = labelwidth;
prog->barwidth = barwidth;
prog->flags = flags;
prog->maxdone = maxdone;
prog->current = 0;
prog->shown = 0;
prog->f = stdout;
*ret_prog = prog;
return ext2fs_progress_display(prog);
}
void ext2fs_progress_close(ext2_sim_progmeter prog)
{
if (prog->label)
free(prog->label);
free(prog);
printf("\n");
return;
}

113
resize/test_extent.c Normal file
View File

@ -0,0 +1,113 @@
/*
* test_extent.c --- tester for the extent abstraction
*
* Copyright (C) 1997 Theodore Ts'o
*
* %Begin-Header%
* All rights reserved.
* %End-Header%
*/
#include "resize2fs.h"
void do_test(FILE *in, FILE *out);
void do_test(FILE *in, FILE *out)
{
char buf[128];
char *cp, *cmd, *arg1, *arg2;
__u32 num1, num2;
int size;
errcode_t retval;
ext2_extent extent = 0;
const char *no_table = "# No extent table\n";
while (!feof(in)) {
if (!fgets(buf, sizeof(buf), in))
break;
/*
* Ignore comments
*/
if (buf[0] =='#')
continue;
/*
* Echo command
*/
fputs(buf, out);
cp = strchr(buf, '\n');
if (cp)
*cp = '\0';
/*
* Parse command line; simple, at most two arguments
*/
cmd = buf;
num1 = num2 = 0;
arg1 = arg2 = 0;
cp = strchr(buf, ' ');
if (cp) {
*cp++ = '\0';
arg1 = cp;
num1 = strtoul(arg1, 0, 0);
cp = strchr(cp, ' ');
}
if (cp) {
*cp++ = '\0';
arg2 = cp;
num2 = strtoul(arg2, 0, 0);
}
if (!strcmp(cmd, "create")) {
retval = ext2fs_create_extent_table(&extent, num1);
if (retval) {
handle_error:
fprintf(out, "# Error: %s\n",
error_message(retval));
continue;
}
continue;
}
if (!extent) {
fputs(no_table, out);
continue;
}
if (!strcmp(cmd, "free")) {
ext2fs_free_extent_table(extent);
extent = 0;
} else if (!strcmp(cmd, "add")) {
retval = ext2fs_add_extent_entry(extent, num1, num2);
if (retval)
goto handle_error;
} else if (!strcmp(cmd, "lookup")) {
num2 = ext2fs_extent_translate(extent, num1);
fprintf(out, "# Answer: %u%s\n", num2,
num2 ? "" : " (not found)");
} else if (!strcmp(cmd, "dump")) {
ext2fs_extent_dump(extent, out);
} else if (!strcmp(cmd, "iter_test")) {
retval = ext2fs_iterate_extent(extent, 0, 0, 0);
if (retval)
goto handle_error;
while (1) {
retval = ext2fs_iterate_extent(extent,
&num1, &num2, &size);
if (retval)
goto handle_error;
if (!size)
break;
fprintf(out, "# %u -> %u (%d)\n",
num1, num2, size);
}
} else
fputs("# Syntax error\n", out);
}
}
int main(int argc, char **argv)
{
do_test(stdin, stdout);
exit(0);
}

64
resize/test_extent.in Normal file
View File

@ -0,0 +1,64 @@
create 10
add 10 20
add 11 21
add 12 22
add 14 45
add 16 50
add 17 51
dump
# Extent dump:
# Num=3, Size=10, Cursor=0, Sorted=1
# 10 -> 20 (3)
# 14 -> 45 (1)
# 16 -> 50 (2)
add 18 52
dump
# Extent dump:
# Num=3, Size=10, Cursor=0, Sorted=1
# 10 -> 20 (3)
# 14 -> 45 (1)
# 16 -> 50 (3)
lookup 10
# Answer: 20
lookup 11
# Answer: 21
lookup 12
# Answer: 22
lookup 13
# Answer: 0 (not found)
lookup 14
# Answer: 45
lookup 15
# Answer: 0 (not found)
lookup 16
# Answer: 50
lookup 1
# Answer: 0 (not found)
lookup 50
# Answer: 0 (not found)
add 19 100
add 13 5
lookup 18
# Answer: 52
lookup 19
# Answer: 100
lookup 20
# Answer: 0 (not found)
lookup 12
# Answer: 22
lookup 13
# Answer: 5
dump
# Extent dump:
# Num=5, Size=10, Cursor=0, Sorted=1
# 10 -> 20 (3)
# 13 -> 5 (1)
# 14 -> 45 (1)
# 16 -> 50 (3)
# 19 -> 100 (1)
iter_test
# 10 -> 20 (3)
# 13 -> 5 (1)
# 14 -> 45 (1)
# 16 -> 50 (3)
# 19 -> 100 (1)