mirror of https://github.com/vitalif/e2fsprogs
Many files:
Checkin of work to date. (Pretty much completely working now.)bitmap-optimize
parent
05e112a11b
commit
c762c8e632
|
@ -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
|
||||
|
|
|
@ -1,8 +1,2 @@
|
|||
TODO
|
||||
|
||||
*) Inode table relocation
|
||||
|
||||
*) Inode relocation
|
||||
|
||||
*) Summary information collection
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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)
|
Loading…
Reference in New Issue