Whamcloud - gitweb
Many files:
authorTheodore Ts'o <tytso@mit.edu>
Mon, 9 Jun 1997 14:51:29 +0000 (14:51 +0000)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 9 Jun 1997 14:51:29 +0000 (14:51 +0000)
  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.

15 files changed:
lib/ext2fs/ChangeLog
lib/ext2fs/Makefile.in
lib/ext2fs/alloc_tables.c
lib/ext2fs/bitmaps.c
lib/ext2fs/bmove.c [new file with mode: 0644]
lib/ext2fs/brel.h
lib/ext2fs/dblist.c
lib/ext2fs/ext2fs.h
lib/ext2fs/rs_bitmap.c
resize/Makefile.in
resize/NOTES [new file with mode: 0644]
resize/banalysis.c
resize/main.c
resize/resize2fs.c
resize/resize2fs.h

index f8fb703..b9f4177 100644 (file)
@@ -1,3 +1,27 @@
+Mon Jun  9 10:45:48 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * bmove.c (ext2fs_move_blocks): New function which takes a bitmap
+               of blocks which need to be moved, and moves those blocks
+               to another location in the filesystem.
+
+       * rs_bitmap.c (ext2fs_resize_generic_bitmap): When expanding a
+               bitmap, make sure all of the new parts of the bitmap are
+               zero. 
+
+Sun Jun  8 16:24:39 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
+
+       * bitmaps.c (ext2fs_copy_bitmap): Fix bug; the destination bitmap
+               wasn't being returned to the caller.
+
+       * alloc_tables.c (ext2fs_allocate_group_table): Add new function
+               ext2fs_allocate_group_table() which sets the group tables
+               for a particular block group.  The relevant code was
+               factored out of ext2fs_allocate_tables().
+
+       * dblist.c (make_dblist): Adjust the initial size of the directory
+               block list to be a bit more realize (ten plus twice the
+               number of directories in the filesystem).
+
 Thu May  8 22:19:09 1997  Theodore Ts'o  <tytso@rsts-11.mit.edu>
 
        * badblocks.c (ext2fs_badblocks_list_test): Fix bug where
index 4e220c6..a43f814 100644 (file)
@@ -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 \
index 6a60bf7..1c88557 100644 (file)
 
 #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;
 }
index c3a778d..defa0cd 100644 (file)
@@ -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 (file)
index 0000000..8e8ad48
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * bmove.c --- Move blocks around to make way for a particular
+ *     filesystem structure.
+ *
+ * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
+ * under the terms of the GNU Public License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+
+#include <linux/ext2_fs.h>
+#include "ext2fs/ext2fs.h"
+
+struct process_block_struct {
+       ino_t                   ino;
+       struct ext2_inode *     inode;
+       ext2fs_block_bitmap     reserve;
+       errcode_t               error;
+       char                    *buf;
+       int                     add_dir;
+};
+
+static int process_block(ext2_filsys fs, blk_t *block_nr,
+                        int blockcnt, blk_t ref_block,
+                        int ref_offset, void *private)
+{
+       struct process_block_struct *pb = private;
+       errcode_t       retval;
+       int             ret;
+       blk_t           block, orig;
+
+       block = orig = *block_nr;
+       ret = 0;
+       
+       /*
+        * Let's see if this is one which we need to relocate
+        */
+       if (ext2fs_test_block_bitmap(pb->reserve, block)) {
+               do {
+                       if (++block >= fs->super->s_blocks_count)
+                               block = fs->super->s_first_data_block;
+                       if (block == orig) {
+                               pb->error = ENOSPC;
+                               return BLOCK_ABORT;
+                       }
+               } while (ext2fs_test_block_bitmap(pb->reserve, block) ||
+                        ext2fs_test_block_bitmap(fs->block_map, block));
+
+               retval = io_channel_read_blk(fs->io, orig, 1, pb->buf);
+               if (retval) {
+                       pb->error = retval;
+                       return BLOCK_ABORT;
+               }
+               retval = io_channel_write_blk(fs->io, block, 1, pb->buf);
+               if (retval) {
+                       pb->error = retval;
+                       return BLOCK_ABORT;
+               }
+               *block_nr = block;
+               ext2fs_mark_block_bitmap(fs->block_map, block);
+               ret = BLOCK_CHANGED;
+               printf("ino=%ld, blockcnt=%d, %ld->%ld\n", pb->ino,
+                      blockcnt, orig, block);
+       }
+       if (pb->add_dir) {
+               retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
+                                             block, blockcnt);
+               if (retval) {
+                       pb->error = retval;
+                       ret |= BLOCK_ABORT;
+               }
+       }
+       return ret;
+}
+
+errcode_t ext2fs_move_blocks(ext2_filsys fs,
+                            ext2fs_block_bitmap reserve,
+                            int flags)
+{
+       ino_t   ino;
+       struct ext2_inode inode;
+       errcode_t       retval;
+       struct process_block_struct pb;
+       ext2_inode_scan scan;
+       char            *block_buf;
+       
+       retval = ext2fs_open_inode_scan(fs, 0, &scan);
+       if (retval)
+               return retval;
+
+       pb.reserve = reserve;
+       pb.error = 0;
+       
+       block_buf = malloc(fs->blocksize * 4);
+       if (!block_buf)
+               return ENOMEM;
+       pb.buf = block_buf + fs->blocksize * 3;
+
+       /*
+        * If GET_DBLIST is set in the flags field, then we should
+        * gather directory block information while we're doing the
+        * block move.
+        */
+       if (flags & EXT2_BMOVE_GET_DBLIST) {
+               if (fs->dblist) {
+                       ext2fs_free_dblist(fs->dblist);
+                       fs->dblist = NULL;
+               }
+               retval = ext2fs_init_dblist(fs, 0);
+               if (retval)
+                       return retval;
+       }
+
+       retval = ext2fs_get_next_inode(scan, &ino, &inode);
+       if (retval)
+               return retval;
+       
+       while (ino) {
+               if ((inode.i_links_count == 0) ||
+                   !ext2fs_inode_has_valid_blocks(&inode))
+                       goto next;
+               
+               pb.ino = ino;
+               pb.inode = &inode;
+
+               pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
+                             flags & EXT2_BMOVE_GET_DBLIST);
+
+               retval = ext2fs_block_iterate2(fs, ino, 0, block_buf,
+                                             process_block, &pb);
+               if (retval)
+                       return retval;
+               if (pb.error)
+                       return pb.error;
+
+       next:
+               retval = ext2fs_get_next_inode(scan, &ino, &inode);
+               if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
+                       goto next;
+       }
+       return 0;
+}
+
index f31b7ae..22089c3 100644 (file)
@@ -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;
 
index f990c10..80e1f05 100644 (file)
@@ -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;
index 2e68c4c..f3d136a 100644 (file)
@@ -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);
 
index 9017853..c41b5e6 100644 (file)
@@ -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;
index a57ee3b..9f5c2cc 100644 (file)
@@ -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 (file)
index 0000000..e04d180
--- /dev/null
@@ -0,0 +1,8 @@
+TODO
+
+*) Inode table relocation
+
+*) Inode relocation
+
+*) Summary information collection
+
index 233158b..5b02d22 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * banalysis.c --- Analyze a filesystem for a block struct
+ * banalysis.c --- Analyze a filesystem by block 
  *
  * Copyright (C) 1997 Theodore Ts'o.  This file may be redistributed
  * under the terms of the GNU Public License.
@@ -12,9 +12,6 @@
 #include <sys/types.h>
 #include <sys/time.h>
 
-#ifdef HAVE_LINUX_FS_H
-#include <linux/fs.h>
-#endif
 #include <linux/ext2_fs.h>
 
 #include "ext2fs/ext2fs.h"
@@ -28,31 +25,6 @@ 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;
 }
+
index b664664..d8b2200 100644 (file)
@@ -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);
 }
index 3c91547..b2fbc68 100644 (file)
@@ -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;
 }
index 1c90db1..5c1dad3 100644 (file)
@@ -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;