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