mirror of https://github.com/vitalif/e2fsprogs
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.bitmap-optimize
parent
24b2c7a7a1
commit
1e1da29fbd
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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(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;
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_mark_block_bitmap(fs->block_map, new_blk);
|
||||
fs->group_desc[i].bg_inode_bitmap = new_blk;
|
||||
|
||||
/*
|
||||
* Increment the start of the block group
|
||||
*/
|
||||
group_blk += fs->super->s_blocks_per_group;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -198,6 +198,11 @@ struct struct_ext2_filsys {
|
|||
#define BLOCK_COUNT_TIND (-3)
|
||||
#define BLOCK_COUNT_TRANSLATOR (-4)
|
||||
|
||||
/*
|
||||
* Flags for ext2fs_move_blocks
|
||||
*/
|
||||
#define EXT2_BMOVE_GET_DBLIST 0x0001
|
||||
|
||||
/*
|
||||
* Return flags for the directory iterator functions
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 $@
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
TODO
|
||||
|
||||
*) Inode table relocation
|
||||
|
||||
*) Inode relocation
|
||||
|
||||
*) Summary information collection
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
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;
|
||||
|
||||
retval = ext2fs_allocate_group_table(fs, i, 0);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
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;
|
||||
}
|
||||
group_block += fs->super->s_blocks_per_group;
|
||||
}
|
||||
|
||||
return 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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
end_blk -= move_by;
|
||||
fs->group_desc[i].bg_inode_table += move_by;
|
||||
}
|
||||
for (blk = start_blk; blk < end_blk; blk++)
|
||||
reserve_block(rfs, blk);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* 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,50 +236,111 @@ 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;
|
||||
continue;
|
||||
}
|
||||
make_way_for_descriptors(rfs, i, group_blk);
|
||||
group_blk += rfs->new_fs->super->s_blocks_per_group;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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);
|
||||
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;
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* This is the top-level routine which does the dirty deed....
|
||||
*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue