diff options
author | Theodore Ts'o <tytso@mit.edu> | 1998-02-16 22:16:20 +0000 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 1998-02-16 22:16:20 +0000 |
commit | a8519a2dbec429846d89fee581a2ecb829904cd2 (patch) | |
tree | 58f250fc072a90f521bf0a68c236b47d2106d7e1 /resize | |
parent | 9abd2ce914f9373fb676f0bb620ffba3a0e3c49e (diff) | |
download | e2fsprogs-a8519a2dbec429846d89fee581a2ecb829904cd2.tar.gz |
Many files:
Major reoganization of how resizing works. Functions in
ext2_block_move.c, and ext2_inode_move.c moved into resize2fs.c.
Multiple passes in those two files also combined into a single inode
scanning pass. Made the inode table moving function better handling
the case where it needs to abort mid-operation. When moving blocks
around, made the block allocation function preferentially avoid the
old group descriptor blocks, to make resize2fs more robust.
Diffstat (limited to 'resize')
-rw-r--r-- | resize/ChangeLog | 13 | ||||
-rw-r--r-- | resize/Makefile.in | 5 | ||||
-rw-r--r-- | resize/NOTES | 2 | ||||
-rw-r--r-- | resize/banalysis.c | 114 | ||||
-rw-r--r-- | resize/banalysis.h | 30 | ||||
-rw-r--r-- | resize/ext2_block_move.c | 222 | ||||
-rw-r--r-- | resize/ext2_inode_move.c | 287 | ||||
-rw-r--r-- | resize/main.c | 21 | ||||
-rw-r--r-- | resize/resize2fs.c | 786 | ||||
-rw-r--r-- | resize/resize2fs.h | 25 |
10 files changed, 678 insertions, 827 deletions
diff --git a/resize/ChangeLog b/resize/ChangeLog index d3c98f09..8c54be7c 100644 --- a/resize/ChangeLog +++ b/resize/ChangeLog @@ -1,3 +1,16 @@ +Mon Feb 16 17:13:01 1998 Theodore Ts'o <tytso@rsts-11.mit.edu> + + * resize2fs.c, resize2fs.h, main.c, ext2_block_move.c, + ext2_inode_move.c: Major reoganization of how resizing + works. Functions in ext2_block_move.c, and + ext2_inode_move.c moved into resize2fs.c. Multiple passes + in those two files also combined into a single inode + scanning pass. Made the inode table moving function + better handling the case where it needs to abort + mid-operation. When moving blocks around, made the block + allocation function preferentially avoid the old group + descriptor blocks, to make resize2fs more robust. + Fri Feb 13 17:15:43 1998 Theodore Ts'o <tytso@rsts-11.mit.edu> * resize2fs.c, resize2fs.h, ext2_block_move.c, ext2_inode_move.c, diff --git a/resize/Makefile.in b/resize/Makefile.in index deabd914..7a748661 100644 --- a/resize/Makefile.in +++ b/resize/Makefile.in @@ -15,14 +15,11 @@ PROGS= resize2fs TEST_PROGS= test_extent MANPAGES= resize2fs.8 -RESIZE_OBJS= extent.o ext2_block_move.o ext2_inode_move.o resize2fs.o \ - main.o sim_progress.o +RESIZE_OBJS= extent.o resize2fs.o main.o sim_progress.o 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)/sim_progress.c diff --git a/resize/NOTES b/resize/NOTES deleted file mode 100644 index ccbf8103..00000000 --- a/resize/NOTES +++ /dev/null @@ -1,2 +0,0 @@ -TODO - diff --git a/resize/banalysis.c b/resize/banalysis.c deleted file mode 100644 index 638ed758..00000000 --- a/resize/banalysis.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * banalysis.c --- Analyze a filesystem by block - * - * Copyright (C) 1997 Theodore Ts'o. This file may be redistributed - * under the terms of the GNU Public License. - */ - -#include <stdio.h> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/time.h> - -#include <linux/ext2_fs.h> - -#include "ext2fs/ext2fs.h" - -#include "ext2fs/brel.h" -#include "banalysis.h" - -struct process_block_struct { - struct ext2_block_analyzer_funcs *funcs; - struct ext2_inode_context *ctx; - void *priv_data; -}; - -static int process_block(ext2_filsys fs, blk_t *block_nr, - int blockcnt, blk_t ref_block, - int ref_offset, void *priv_data) -{ - struct process_block_struct *pb = priv_data; - blk_t new_block; - struct ext2_block_relocate_entry ent; - - if (ref_block == 0) - ref_offset = blockcnt; - - new_block = pb->funcs->block_analyze(fs, *block_nr, ref_block, - ref_offset, pb->ctx, pb->priv_data); - if (new_block) { - ent.new = new_block; - ent.offset = ref_offset; - if (ref_block) { - ent.owner.block_ref = ref_block; - ent.flags = 0; - } else { - ent.owner.inode_ref = pb->ctx->ino; - ent.flags = RELOCATE_INODE_REF; - } - ext2fs_brel_put(pb->ctx->brel, *block_nr, &ent); - } - return 0; -} - -errcode_t ext2_block_analyze(ext2_filsys fs, - struct ext2_block_analyzer_funcs *funcs, - ext2_brel block_relocation_table, - void *priv_data) -{ - ino_t ino; - struct ext2_inode inode; - errcode_t retval; - struct process_block_struct pb; - struct ext2_inode_context ctx; - ext2_inode_scan scan; - char *block_buf; - - retval = ext2fs_open_inode_scan(fs, 0, &scan); - if (retval) - return retval; - - pb.funcs = funcs; - pb.priv_data = priv_data; - pb.ctx = &ctx; - - block_buf = malloc(fs->blocksize * 3); - if (!block_buf) - return ENOMEM; - - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval) - return retval; - ctx.ctx = priv_data; - ctx.brel = block_relocation_table; - while (ino) { - if ((inode.i_links_count == 0) || - !ext2fs_inode_has_valid_blocks(&inode)) - goto next; - - ctx.ino = ino; - ctx.inode = &inode; - ctx.error = 0; - - if (funcs->pre_analyze && - !(*funcs->pre_analyze)(fs, &ctx, priv_data)) - goto next; - - retval = ext2fs_block_iterate2(fs, ino, 0, block_buf, - process_block, &pb); - if (retval) - return retval; - - if (funcs->post_analyze) - (funcs->post_analyze)(fs, &ctx, priv_data); - - next: - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) - goto next; - } - return 0; -} - diff --git a/resize/banalysis.h b/resize/banalysis.h deleted file mode 100644 index 18cf98ec..00000000 --- a/resize/banalysis.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * banalysis.h --- Block analysis header file - */ - -struct ext2_inode_context { - ino_t ino; - struct ext2_inode * inode; - errcode_t error; - ext2_brel brel; - void * ctx; -}; - -struct ext2_block_analyzer_funcs { - int (*pre_analyze)(ext2_filsys fs, - struct ext2_inode_context *icontext, - void *priv_data); - blk_t (*block_analyze)(ext2_filsys fs, blk_t blk, - blk_t ref_block, int ref_offset, - struct ext2_inode_context *icontext, - void *priv_data); - void (*post_analyze)(ext2_filsys fs, - struct ext2_inode_context *icontext, - void *priv_data); -}; - -errcode_t ext2_block_analyze(ext2_filsys fs, - struct ext2_block_analyzer_funcs *funcs, - ext2_brel block_relocation_table, - void *priv_data); - diff --git a/resize/ext2_block_move.c b/resize/ext2_block_move.c deleted file mode 100644 index e61c9d97..00000000 --- a/resize/ext2_block_move.c +++ /dev/null @@ -1,222 +0,0 @@ -/* - * 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 *priv_data) -{ - struct process_block_struct *pb; - errcode_t retval; - blk_t block, new_block; - int ret = 0; - - pb = (struct process_block_struct *) priv_data; - block = *block_nr; - new_block = ext2fs_extent_translate(pb->bmap, block); - if (new_block) { - *block_nr = new_block; - ret |= BLOCK_CHANGED; -#ifdef RESIZE2FS_DEBUG - if (pb->flags & RESIZE_DEBUG_BMOVE) - printf("ino=%ld, blockcnt=%d, %u->%u\n", pb->ino, - blockcnt, block, new_block); -#endif - } - - 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_blk, new_blk; - 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 = 0; - int size, c; - int to_move, moved; - - new_blk = fs->super->s_first_data_block; - if (!rfs->itable_buf) { - retval = ext2fs_get_mem(fs->blocksize * - fs->inode_blocks_per_group, - (void **) &rfs->itable_buf); - if (retval) - return retval; - } - 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_blk >= fs->super->s_blocks_count) { - retval = ENOSPC; - goto errout; - } - if (!ext2fs_test_block_bitmap(fs->block_map, new_blk) && - !ext2fs_test_block_bitmap(rfs->reserve_blocks, - new_blk)) - break; - new_blk++; - } - ext2fs_mark_block_bitmap(fs->block_map, new_blk); - ext2fs_add_extent_entry(bmap, blk, new_blk); - 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->progress) - (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS, 0, to_move); - - while (1) { - retval = ext2fs_iterate_extent(bmap, &old_blk, &new_blk, &size); - if (retval) goto errout; - if (!size) - break; -#ifdef RESIZE2FS_DEBUG - if (rfs->flags & RESIZE_DEBUG_BMOVE) - printf("Moving %d blocks %u->%u\n", size, - old_blk, new_blk); -#endif - do { - c = size; - if (c > fs->inode_blocks_per_group) - c = fs->inode_blocks_per_group; - retval = io_channel_read_blk(fs->io, old_blk, c, - rfs->itable_buf); - if (retval) goto errout; - retval = io_channel_write_blk(fs->io, new_blk, c, - rfs->itable_buf); - if (retval) goto errout; - size -= c; - new_blk += c; - old_blk += c; - moved += c; - io_channel_flush(fs->io); - if (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS, - moved, to_move); - } while (size > 0); - io_channel_flush(fs->io); - } - - /* - * 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; - - retval = ext2fs_get_mem(old_fs->blocksize * 3, (void **) &block_buf); - if (retval) - 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->progress) - (rfs->progress)(rfs, E2_RSZ_BLOCK_REF_UPD_PASS, - 0, old_fs->super->s_inodes_count); - - 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 (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_BLOCK_REF_UPD_PASS, - ino, old_fs->super->s_inodes_count); - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) - goto next; - } - retval = 0; -errout: - - ext2fs_free_extent_table(bmap); - if (scan) - ext2fs_close_inode_scan(scan); - if (block_buf) - ext2fs_free_mem((void **) &block_buf); - return retval; -} - diff --git a/resize/ext2_inode_move.c b/resize/ext2_inode_move.c deleted file mode 100644 index eae7aa35..00000000 --- a/resize/ext2_inode_move.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * ext2_inode_move.c --- ext2resizer inode mover - * - * Copyright (C) 1997 Theodore Ts'o - * - * %Begin-Header% - * All rights reserved. - * %End-Header% - */ - -#include "resize2fs.h" - -struct istruct { - ext2_resize_t rfs; - unsigned long max; - 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 *priv_data) -{ - struct istruct *is = (struct istruct *) priv_data; - ino_t new_inode; - - if (is->rfs->progress && offset == 0) { - (is->rfs->progress)(is->rfs, E2_RSZ_INODE_REF_UPD_PASS, - ++is->num, is->max); - } - - if (!dirent->inode) - return 0; - - new_inode = ext2fs_extent_translate(is->imap, dirent->inode); - - if (!new_inode) - return 0; -#ifdef RESIZE2FS_DEBUG - 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_inode); -#endif - - dirent->inode = new_inode; - - 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 *priv_data) -{ - struct process_block_struct *pb; - errcode_t retval; - int ret = 0; - - pb = (struct process_block_struct *) priv_data; - 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_resize_t rfs) -{ - ext2_inode_scan scan = 0; - errcode_t retval; - char *block_buf = 0; - struct process_block_struct pb; - ino_t ino; - struct ext2_inode inode; - ext2_filsys fs = rfs->old_fs; - - retval = ext2fs_open_inode_scan(fs, 0, &scan); - if (retval) goto errout; - - pb.error = 0; - - retval = ext2fs_get_mem(fs->blocksize * 3, (void **) &block_buf); - if (retval) - 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 (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_INODE_FIND_DIR_PASS, - 0, fs->super->s_inodes_count); - - 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 (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_INODE_FIND_DIR_PASS, - ino, fs->super->s_inodes_count); - retval = ext2fs_get_next_inode(scan, &ino, &inode); - if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE) - goto next; - } - retval = 0; - -errout: - if (scan) - ext2fs_close_inode_scan(scan); - if (block_buf) - ext2fs_free_mem((void **) &block_buf); - return retval; -} - -/* - * Progress callback - */ -struct callback_info { - ext2_resize_t rfs; - unsigned long max; - int offset; -}; - -static errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan, - dgrp_t group, void * priv_data) -{ - struct callback_info *cb = (struct callback_info *) priv_data; - - if (cb->rfs->progress) - (cb->rfs->progress)(cb->rfs, E2_RSZ_INODE_RELOC_PASS, - group - cb->offset + 1, cb->max); - - return 0; -} - -errcode_t ext2fs_inode_move(ext2_resize_t rfs) -{ - ino_t ino, new_inode; - 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; - - 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; - - callback_info.offset = rfs->new_fs->group_desc_count; - callback_info.max = (rfs->old_fs->group_desc_count - - rfs->new_fs->group_desc_count); - callback_info.rfs = rfs; - if (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_INODE_RELOC_PASS, - 0, callback_info.max); - - ext2fs_set_inode_callback(scan, progress_callback, - &callback_info); - - new_inode = 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_inode)) - break; - new_inode++; - if (new_inode > rfs->new_fs->super->s_inodes_count) { - retval = ENOSPC; - goto errout; - } - } - ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode); - retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode); - if (retval) goto errout; - - group = (new_inode-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++; - -#ifdef RESIZE2FS_DEBUG - if (rfs->flags & RESIZE_DEBUG_INODEMAP) - printf("Inode moved %ld->%ld\n", ino, new_inode); -#endif - - ext2fs_add_extent_entry(imap, ino, new_inode); - } - io_channel_flush(rfs->new_fs->io); - /* - * Get the list of directory blocks, if necessary - */ - if (!rfs->old_fs->dblist) { - retval = get_dblist(rfs); - if (retval) goto errout; - } - /* - * Now, we iterate over all of the directories to update the - * inode references - */ - is.imap = imap; - is.flags = rfs->flags; - is.num = 0; - is.max = ext2fs_dblist_count(rfs->old_fs->dblist); - is.rfs = rfs; - - if (rfs->progress) - (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS, - 0, is.max); - - retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist, - DIRENT_FLAG_INCLUDE_EMPTY, 0, - check_and_change_inodes, &is); - /* if (retval) goto errout; */ - -errout: - ext2fs_free_extent_table(imap); - if (scan) - ext2fs_close_inode_scan(scan); - return retval; -} - diff --git a/resize/main.c b/resize/main.c index 5035ab05..c547f070 100644 --- a/resize/main.c +++ b/resize/main.c @@ -41,20 +41,14 @@ static void resize_progress_func(ext2_resize_t rfs, int pass, ext2fs_progress_close(progress); progress = 0; switch (pass) { - case E2_RSZ_ADJUST_SUPERBLOCK_PASS: - label = "Initializing inode table"; + case E2_RSZ_EXTEND_ITABLE_PASS: + label = "Extending the inode table"; break; case E2_RSZ_BLOCK_RELOC_PASS: label = "Relocating blocks"; break; - case E2_RSZ_BLOCK_REF_UPD_PASS: - label = "Updating block references"; - break; - case E2_RSZ_INODE_FIND_DIR_PASS: - label = "Finding directories"; - break; - case E2_RSZ_INODE_RELOC_PASS: - label = "Moving inodes"; + case E2_RSZ_INODE_SCAN_PASS: + label = "Scanning inode table"; break; case E2_RSZ_INODE_REF_UPD_PASS: label = "Updating inode references"; @@ -62,6 +56,9 @@ static void resize_progress_func(ext2_resize_t rfs, int pass, case E2_RSZ_MOVE_ITABLE_PASS: label = "Moving inode table"; break; + default: + label = "Unknown pass?!?"; + break; } printf("Begin pass %d (max = %lu)\n", pass, max); retval = ext2fs_progress_init(&progress, label, 30, @@ -156,7 +153,9 @@ void main (int argc, char ** argv) printf ("Couldn't find valid filesystem superblock.\n"); exit (1); } - retval = resize_fs(fs, new_size, flags, resize_progress_func); + retval = resize_fs(fs, new_size, flags, + ((flags & RESIZE_PERCENT_COMPLETE) ? + resize_progress_func : 0)); if (retval) { com_err(program_name, retval, "while trying to resize %s", device_name); diff --git a/resize/resize2fs.c b/resize/resize2fs.c index 243ab03f..cffc3557 100644 --- a/resize/resize2fs.c +++ b/resize/resize2fs.c @@ -11,17 +11,155 @@ /* * Resizing a filesystem consists of the following phases: * - * 1. Adjust superblock and (*) write out new parts of the inode + * 1. Adjust superblock and write out new parts of the inode * table - * 2. Determine blocks which need to be relocated. - * 3. (*) Relocate blocks which must be moved, adjusting entries - * in the filesystem in the process. - * 4. (*) Move inodes which must be moved (only when shrinking a - * filesystem) - * 5. (*) Move the inode tables, if necessary. + * 2. Determine blocks which need to be relocated, and copy the + * contents of blocks from their old locations to the new ones. + * 3. Scan the inode table, doing the following: + * a. If blocks have been moved, update the block + * pointers in the inodes and indirect blocks to + * point at the new block locations. + * b. If parts of the inode table need to be evacuated, + * copy inodes from their old locations to their + * new ones. + * c. If (b) needs to be done, note which blocks contain + * directory information, since we will need to + * update the directory information. + * 4. Update the directory blocks with the new inode locations. + * 5. Move the inode tables, if necessary. */ + #include "resize2fs.h" +#ifdef linux /* Kludge for debugging */ +#define RESIZE2FS_DEBUG +#endif + +static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size); +static errcode_t blocks_to_move(ext2_resize_t rfs); +static errcode_t block_mover(ext2_resize_t rfs); +static errcode_t inode_scan_and_fix(ext2_resize_t rfs); +static errcode_t inode_ref_fix(ext2_resize_t rfs); +static errcode_t move_itables(ext2_resize_t rfs); +static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs); + +/* + * 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 is the top-level routine which does the dirty deed.... + */ +errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags, + void (*progress)(ext2_resize_t rfs, int pass, + unsigned long cur, + unsigned long max)) +{ + ext2_resize_t rfs; + errcode_t retval; + + retval = ext2fs_read_bitmaps(fs); + if (retval) + return retval; + + /* + * Create the data structure + */ + retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), + (void **) &rfs); + if (retval) + return retval; + memset(rfs, 0, sizeof(struct ext2_resize_struct)); + + rfs->old_fs = fs; + rfs->flags = flags; + rfs->itable_buf = 0; + rfs->progress = progress; + retval = ext2fs_dup_handle(fs, &rfs->new_fs); + if (retval) + goto errout; + + retval = adjust_superblock(rfs, new_size); + if (retval) + goto errout; + + retval = blocks_to_move(rfs); + if (retval) + goto errout; + +#ifdef RESIZE2FS_DEBUG + if (rfs->flags & RESIZE_DEBUG_BMOVE) + 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); +#endif + + retval = block_mover(rfs); + if (retval) + goto errout; + + retval = inode_scan_and_fix(rfs); + if (retval) + goto errout; + + retval = inode_ref_fix(rfs); + if (retval) + goto errout; + + retval = ext2fs_calculate_summary_stats(rfs->new_fs); + if (retval) + goto errout; + + retval = move_itables(rfs); + if (retval) + goto errout; + + retval = ext2fs_close(rfs->new_fs); + if (retval) + goto errout; + + rfs->flags = flags; + + ext2fs_free(rfs->old_fs); + if (rfs->itable_buf) + ext2fs_free_mem((void **) &rfs->itable_buf); + ext2fs_free_mem((void **) &rfs); + + return 0; + +errout: + if (rfs->new_fs) + ext2fs_free(rfs->new_fs); + if (rfs->itable_buf) + ext2fs_free_mem((void **) &rfs->itable_buf); + ext2fs_free_mem((void **) &rfs); + return retval; +} + +/* -------------------------------------------------------------------- + * + * Resize processing, phase 1. + * + * In this phase we adjust the in-memory superblock information, and + * initialize any new parts of the inode table. The new parts of the + * inode table are created in virgin disk space, so we can abort here + * without any side effects. + * -------------------------------------------------------------------- + */ + /* * This routine adjusts the superblock and other data structures... */ @@ -126,16 +264,30 @@ retry: retval = ext2fs_resize_mem(fs->desc_blocks * fs->blocksize, (void **) &fs->group_desc); if (retval) - return retval; + goto errout; } /* - * Fix the count of the last (old) block group + * Check to make sure there are enough inodes + */ + if ((rfs->old_fs->super->s_inodes_count - + rfs->old_fs->super->s_free_inodes_count) > + rfs->new_fs->super->s_inodes_count) { + retval = ENOSPC; + goto errout; + } + + /* + * If we are shrinking the number block groups, we're done and + * can exit now. */ if (rfs->old_fs->group_desc_count > fs->group_desc_count) { retval = 0; goto errout; } + /* + * Fix the count of the last (old) block group + */ 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; @@ -153,12 +305,17 @@ retry: fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks); /* - * Initialize the new block group descriptors + * If the number of block groups is staying the same, we're + * done and can exit now. (If the number block groups is + * shrinking, we had exited earlier.) */ if (rfs->old_fs->group_desc_count >= fs->group_desc_count) { retval = 0; goto errout; } + /* + * Initialize the new block group descriptors + */ retval = ext2fs_get_mem(fs->blocksize * fs->inode_blocks_per_group, (void **) &rfs->itable_buf); if (retval) @@ -171,7 +328,7 @@ retry: adj = rfs->old_fs->group_desc_count; max_group = fs->group_desc_count - adj; if (rfs->progress) - rfs->progress(rfs, E2_RSZ_ADJUST_SUPERBLOCK_PASS, + rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS, 0, max_group); for (i = rfs->old_fs->group_desc_count; i < fs->group_desc_count; i++) { @@ -217,9 +374,9 @@ retry: rfs->itable_buf); if (retval) goto errout; - /* io_channel_flush(fs->io); */ + io_channel_flush(fs->io); if (rfs->progress) - rfs->progress(rfs, E2_RSZ_ADJUST_SUPERBLOCK_PASS, + rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS, i - adj + 1, max_group); group_block += fs->super->s_blocks_per_group; @@ -231,6 +388,18 @@ errout: return retval; } +/* -------------------------------------------------------------------- + * + * Resize processing, phase 2. + * + * In this phase we adjust determine which blocks need to be moved, in + * blocks_to_move(). We then copy the blocks to their ultimate new + * destinations using block_mover(). Since we are copying blocks to + * their new locations, again during this pass we can abort without + * any problems. + * -------------------------------------------------------------------- + */ + /* * This helper function creates a block bitmap with all of the * filesystem meta-data blocks. @@ -286,22 +455,6 @@ static errcode_t mark_table_blocks(ext2_filsys fs, 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 @@ -517,6 +670,442 @@ errout: return retval; } +/* + * This helper function tries to allocate a new block. We try to + * avoid hitting the original group descriptor blocks at least at + * first, since we want to make it possible to recover from a badly + * aborted resize operation as much as possible. + * + * In the future, I may further modify this routine to balance out + * where we get the new blocks across the various block groups. + * Ideally we would allocate blocks that corresponded with the block + * group of the containing inode, and keep contiguous blocks + * together. However, this very difficult to do efficiently, since we + * don't have the necessary information up front. + */ + +#define AVOID_OLD 1 +#define DESPERATION 2 + +static void init_block_alloc(ext2_resize_t rfs) +{ + rfs->alloc_state = AVOID_OLD; + rfs->new_blk = rfs->new_fs->super->s_first_data_block; +} + +static blk_t get_new_block(ext2_resize_t rfs) +{ + ext2_filsys fs = rfs->new_fs; + + while (1) { + if (rfs->new_blk >= fs->super->s_blocks_count) { + if (rfs->alloc_state == DESPERATION) + return 0; + +#ifdef RESIZE2FS_DEBUG + if (rfs->flags & RESIZE_DEBUG_BMOVE) + printf("Going into desperation " + "mode for block allocations\n"); +#endif + rfs->alloc_state = DESPERATION; + rfs->new_blk = fs->super->s_first_data_block; + continue; + } + if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) || + ext2fs_test_block_bitmap(rfs->reserve_blocks, + rfs->new_blk) || + ((rfs->alloc_state == AVOID_OLD) && + ext2fs_test_block_bitmap(rfs->old_fs->block_map, + rfs->new_blk))) { + rfs->new_blk++; + continue; + } + return rfs->new_blk; + } +} + +static errcode_t block_mover(ext2_resize_t rfs) +{ + blk_t blk, old_blk, new_blk; + ext2_filsys fs = rfs->new_fs; + ext2_filsys old_fs = rfs->old_fs; + errcode_t retval; + int size, c; + int to_move, moved; + + new_blk = fs->super->s_first_data_block; + if (!rfs->itable_buf) { + retval = ext2fs_get_mem(fs->blocksize * + fs->inode_blocks_per_group, + (void **) &rfs->itable_buf); + if (retval) + return retval; + } + retval = ext2fs_create_extent_table(&rfs->bmap, 0); + if (retval) + return retval; + + /* + * The first step is to figure out where all of the blocks + * will go. + */ + to_move = moved = 0; + init_block_alloc(rfs); + 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; + + new_blk = get_new_block(rfs); + if (!new_blk) { + retval = ENOSPC; + goto errout; + } + ext2fs_mark_block_bitmap(fs->block_map, new_blk); + ext2fs_add_extent_entry(rfs->bmap, blk, new_blk); + to_move++; + } + + if (to_move == 0) { + retval = 0; + goto errout; + } + + /* + * Step two is to actually move the blocks + */ + retval = ext2fs_iterate_extent(rfs->bmap, 0, 0, 0); + if (retval) goto errout; + + if (rfs->progress) + (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS, 0, to_move); + + while (1) { + retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size); + if (retval) goto errout; + if (!size) + break; +#ifdef RESIZE2FS_DEBUG + if (rfs->flags & RESIZE_DEBUG_BMOVE) + printf("Moving %d blocks %u->%u\n", size, + old_blk, new_blk); +#endif + do { + c = size; + if (c > fs->inode_blocks_per_group) + c = fs->inode_blocks_per_group; + retval = io_channel_read_blk(fs->io, old_blk, c, + rfs->itable_buf); + if (retval) goto errout; + retval = io_channel_write_blk(fs->io, new_blk, c, + rfs->itable_buf); + if (retval) goto errout; + size -= c; + new_blk += c; + old_blk += c; + moved += c; + if (rfs->progress) { + io_channel_flush(fs->io); + (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS, + moved, to_move); + } + } while (size > 0); + io_channel_flush(fs->io); + } + +errout: + return retval; +} + + +/* -------------------------------------------------------------------- + * + * Resize processing, phase 3 + * + * -------------------------------------------------------------------- + */ + + +struct process_block_struct { + ext2_resize_t rfs; + ino_t ino; + struct ext2_inode * inode; + errcode_t error; + int is_dir; + int changed; +}; + +static int process_block(ext2_filsys fs, blk_t *block_nr, + int blockcnt, blk_t ref_block, + int ref_offset, void *priv_data) +{ + struct process_block_struct *pb; + errcode_t retval; + blk_t block, new_block; + int ret = 0; + + pb = (struct process_block_struct *) priv_data; + block = *block_nr; + if (pb->rfs->bmap) { + new_block = ext2fs_extent_translate(pb->rfs->bmap, block); + if (new_block) { + *block_nr = new_block; + ret |= BLOCK_CHANGED; + pb->changed = 1; +#ifdef RESIZE2FS_DEBUG + if (pb->rfs->flags & RESIZE_DEBUG_BMOVE) + printf("ino=%ld, blockcnt=%d, %u->%u\n", + pb->ino, blockcnt, block, new_block); +#endif + block = new_block; + } + } + if (pb->is_dir) { + retval = ext2fs_add_dir_block(fs->dblist, pb->ino, + block, blockcnt); + if (retval) { + pb->error = retval; + ret |= BLOCK_ABORT; + } + } + return ret; +} + +/* + * Progress callback + */ +static errcode_t progress_callback(ext2_filsys fs, ext2_inode_scan scan, + dgrp_t group, void * priv_data) +{ + ext2_resize_t rfs = (ext2_resize_t) priv_data; + + /* + * The if (group+1) == 0 test is to protect against old ext2 + * libraries. It shouldn't be needed against new libraries. + */ + if (group == 0 || (group+1) == 0) + return 0; + + if (rfs->progress) { + io_channel_flush(fs->io); + (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS, + group, fs->group_desc_count-1); + } + + return 0; +} + +static errcode_t inode_scan_and_fix(ext2_resize_t rfs) +{ + struct process_block_struct pb; + ino_t ino, new_inode; + struct ext2_inode inode; + ext2_inode_scan scan = NULL; + errcode_t retval; + int group; + char *block_buf = 0; + ino_t start_to_move; + + if ((rfs->old_fs->group_desc_count <= + rfs->new_fs->group_desc_count) && + !rfs->bmap) + return 0; + + retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan); + if (retval) goto errout; + + retval = ext2fs_init_dblist(rfs->old_fs, 0); + if (retval) goto errout; + retval = ext2fs_get_mem(rfs->old_fs->blocksize * 3, + (void **) &block_buf); + if (retval) goto errout; + + start_to_move = (rfs->new_fs->group_desc_count * + rfs->new_fs->super->s_inodes_per_group); + + if (rfs->progress) + (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS, + 0, rfs->old_fs->group_desc_count-1); + + ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs); + pb.rfs = rfs; + pb.inode = &inode; + pb.error = 0; + new_inode = 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 (inode.i_links_count == 0) + continue; /* inode not in use */ + + pb.is_dir = LINUX_S_ISDIR(inode.i_mode); + pb.changed = 0; + + if (ext2fs_inode_has_valid_blocks(&inode) && + (rfs->bmap || pb.is_dir)) { + pb.ino = ino; + retval = ext2fs_block_iterate2(rfs->old_fs, + ino, 0, block_buf, + process_block, &pb); + if (retval) + goto errout; + if (pb.error) { + retval = pb.error; + goto errout; + } + } + + if (ino <= start_to_move) + continue; /* Don't need to move it. */ + + /* + * Find a new inode + */ + while (1) { + if (!ext2fs_test_inode_bitmap(rfs->new_fs->inode_map, + new_inode)) + break; + new_inode++; + if (new_inode > rfs->new_fs->super->s_inodes_count) { + retval = ENOSPC; + goto errout; + } + } + ext2fs_mark_inode_bitmap(rfs->new_fs->inode_map, new_inode); + if (pb.changed) { + /* Get the new version of the inode */ + retval = ext2fs_read_inode(rfs->old_fs, ino, &inode); + if (retval) goto errout; + } + retval = ext2fs_write_inode(rfs->old_fs, new_inode, &inode); + if (retval) goto errout; + + group = (new_inode-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++; + +#ifdef RESIZE2FS_DEBUG + if (rfs->flags & RESIZE_DEBUG_INODEMAP) + printf("Inode moved %ld->%ld\n", ino, new_inode); +#endif + if (!rfs->imap) { + retval = ext2fs_create_extent_table(&rfs->imap, 0); + if (retval) + goto errout; + } + ext2fs_add_extent_entry(rfs->imap, ino, new_inode); + } + io_channel_flush(rfs->old_fs->io); + +errout: + if (rfs->bmap) { + ext2fs_free_extent_table(rfs->bmap); + rfs->bmap = 0; + } + if (scan) + ext2fs_close_inode_scan(scan); + if (block_buf) + ext2fs_free_mem((void **) &block_buf); + return retval; +} + +/* -------------------------------------------------------------------- + * + * Resize processing, phase 4. + * + * -------------------------------------------------------------------- + */ + +struct istruct { + ext2_resize_t rfs; + unsigned long max; + 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 *priv_data) +{ + struct istruct *is = (struct istruct *) priv_data; + ino_t new_inode; + + if (is->rfs->progress && offset == 0) { + io_channel_flush(is->rfs->old_fs->io); + (is->rfs->progress)(is->rfs, E2_RSZ_INODE_REF_UPD_PASS, + ++is->num, is->max); + } + + if (!dirent->inode) + return 0; + + new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode); + + if (!new_inode) + return 0; +#ifdef RESIZE2FS_DEBUG + if (is->rfs->flags & RESIZE_DEBUG_INODEMAP) + printf("Inode translate (dir=%ld, name=%.*s, %u->%ld)\n", + dir, dirent->name_len, dirent->name, + dirent->inode, new_inode); +#endif + + dirent->inode = new_inode; + + return DIRENT_CHANGED; +} + +static errcode_t inode_ref_fix(ext2_resize_t rfs) +{ + errcode_t retval; + struct istruct is; + + if (!rfs->imap) + return 0; + + /* + * Now, we iterate over all of the directories to update the + * inode references + */ + is.num = 0; + is.max = ext2fs_dblist_count(rfs->old_fs->dblist); + is.rfs = rfs; + + if (rfs->progress) + (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS, + 0, is.max); + + retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist, + DIRENT_FLAG_INCLUDE_EMPTY, 0, + check_and_change_inodes, &is); + + ext2fs_free_extent_table(rfs->imap); + rfs->imap = 0; + return retval; +} + + +/* -------------------------------------------------------------------- + * + * Resize processing, phase 5. + * + * In this phase we actually move the inode table around, and then + * update the summary statistics. This is scary, since aborting here + * will potentially scramble the filesystem. (We are moving the + * inode tables around in place, and so the potential for lost data, + * or at the very least scrambling the mapping between filenames and + * inode numbers is very high in case of a power failure here.) + * -------------------------------------------------------------------- + */ + /* * A very scary routine --- this one moves the inode table around!!! @@ -530,7 +1119,7 @@ static errcode_t move_itables(ext2_resize_t rfs) ext2_filsys fs = rfs->new_fs; char *cp; blk_t old_blk, new_blk; - errcode_t retval, err; + errcode_t retval; int to_move, moved; max = fs->group_desc_count; @@ -559,6 +1148,8 @@ static errcode_t move_itables(ext2_resize_t rfs) if (rfs->progress) rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS, 0, to_move); + rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY; + for (i=0; i < max; i++) { old_blk = rfs->old_fs->group_desc[i].bg_inode_table; new_blk = fs->group_desc[i].bg_inode_table; @@ -578,11 +1169,13 @@ static errcode_t move_itables(ext2_resize_t rfs) fs->inode_blocks_per_group, rfs->itable_buf); if (retval) - goto backout; + goto errout; /* * The end of the inode table segment often contains - * all zeros. Find out if we have several blocks of - * zeros so we can optimize the write. + * all zeros, and we're often only moving the inode + * table down a block or two. If so, we can optimize + * things by not rewriting blocks that we know to be zero + * already. */ for (cp = rfs->itable_buf+size, n=0; n < size; n++, cp--) if (*cp) @@ -601,50 +1194,33 @@ static errcode_t move_itables(ext2_resize_t rfs) if (retval) { io_channel_write_blk(fs->io, old_blk, num, rfs->itable_buf); - goto backout; + goto errout; } if (n > diff) { retval = io_channel_write_blk(fs->io, old_blk + fs->inode_blocks_per_group, - diff, rfs->itable_buf - fs->blocksize * diff); + diff, (rfs->itable_buf + + (fs->inode_blocks_per_group - diff) * + fs->blocksize)); if (retval) - goto backout; + goto errout; } - io_channel_flush(fs->io); - if (rfs->progress) + rfs->old_fs->group_desc[i].bg_inode_table = new_blk; + ext2fs_mark_super_dirty(rfs->old_fs); + if (rfs->progress) { + ext2fs_flush(rfs->old_fs); rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS, ++moved, to_move); + } } - ext2fs_flush(rfs->new_fs); - io_channel_flush(fs->io); + ext2fs_flush(fs); #ifdef RESIZE2FS_DEBUG if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) printf("Inode table move finished.\n"); #endif return 0; -backout: -#ifdef RESIZE2FS_DEBUG - if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) - printf("Error: %s; now backing out!\n", error_message(retval)); -#endif - while (--i >= 0) { -#ifdef RESIZE2FS_DEBUG - if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE) - printf("Group %d block %u->%u\n", i, new_blk, old_blk); -#endif - old_blk = rfs->old_fs->group_desc[i].bg_inode_table; - new_blk = fs->group_desc[i].bg_inode_table; - - err = io_channel_read_blk(fs->io, new_blk, - fs->inode_blocks_per_group, - rfs->itable_buf); - if (err) - continue; - err = io_channel_write_blk(fs->io, old_blk, - fs->inode_blocks_per_group, - rfs->itable_buf); - } +errout: return retval; } @@ -705,89 +1281,3 @@ static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs) ext2fs_mark_super_dirty(fs); return 0; } - -/* - * This is the top-level routine which does the dirty deed.... - */ -errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags, - void (*progress)(ext2_resize_t rfs, int pass, - unsigned long cur, - unsigned long max)) -{ - ext2_resize_t rfs; - errcode_t retval; - - retval = ext2fs_read_bitmaps(fs); - if (retval) - return retval; - - /* - * Create the data structure - */ - retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), - (void **) &rfs); - if (retval) - return retval; - memset(rfs, 0, sizeof(struct ext2_resize_struct)); - - rfs->old_fs = fs; - rfs->flags = flags; - rfs->itable_buf = 0; - rfs->progress = progress; - retval = ext2fs_dup_handle(fs, &rfs->new_fs); - if (retval) - goto errout; - - retval = adjust_superblock(rfs, new_size); - if (retval) - goto errout; - - retval = blocks_to_move(rfs); - if (retval) - goto errout; - -#ifdef RESIZE2FS_DEBUG - if (rfs->flags & RESIZE_DEBUG_BMOVE) - 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); -#endif - - retval = ext2fs_block_move(rfs); - if (retval) - goto errout; - - retval = ext2fs_inode_move(rfs); - if (retval) - goto errout; - - retval = move_itables(rfs); - if (retval) - goto errout; - - retval = ext2fs_calculate_summary_stats(rfs->new_fs); - if (retval) - goto errout; - - retval = ext2fs_close(rfs->new_fs); - if (retval) - goto errout; - - rfs->flags = flags; - - ext2fs_free(rfs->old_fs); - if (rfs->itable_buf) - ext2fs_free_mem((void **) &rfs->itable_buf); - ext2fs_free_mem((void **) &rfs); - - return 0; - -errout: - if (rfs->new_fs) - ext2fs_free(rfs->new_fs); - if (rfs->itable_buf) - ext2fs_free_mem((void **) &rfs->itable_buf); - ext2fs_free_mem((void **) &rfs); - return retval; -} diff --git a/resize/resize2fs.h b/resize/resize2fs.h index 769a1b47..5d96353d 100644 --- a/resize/resize2fs.h +++ b/resize/resize2fs.h @@ -66,9 +66,21 @@ struct ext2_resize_struct { ext2_filsys new_fs; ext2fs_block_bitmap reserve_blocks; ext2fs_block_bitmap move_blocks; + ext2_extent bmap; + ext2_extent imap; int needed_blocks; int flags; char *itable_buf; + + /* + * For the block allocator + */ + blk_t new_blk; + int alloc_state; + + /* + * For the progress meter + */ void (*progress)(ext2_resize_t rfs, int pass, unsigned long cur, unsigned long max); @@ -78,13 +90,11 @@ struct ext2_resize_struct { /* * Progress pass numbers... */ -#define E2_RSZ_ADJUST_SUPERBLOCK_PASS 1 +#define E2_RSZ_EXTEND_ITABLE_PASS 1 #define E2_RSZ_BLOCK_RELOC_PASS 2 -#define E2_RSZ_BLOCK_REF_UPD_PASS 3 -#define E2_RSZ_INODE_FIND_DIR_PASS 4 -#define E2_RSZ_INODE_RELOC_PASS 5 -#define E2_RSZ_INODE_REF_UPD_PASS 6 -#define E2_RSZ_MOVE_ITABLE_PASS 7 +#define E2_RSZ_INODE_SCAN_PASS 3 +#define E2_RSZ_INODE_REF_UPD_PASS 4 +#define E2_RSZ_MOVE_ITABLE_PASS 5 /* prototypes */ @@ -93,9 +103,6 @@ extern errcode_t resize_fs(ext2_filsys fs, blk_t new_size, int flags, unsigned long cur, unsigned long max)); -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); |