1997-06-08 00:42:58 +04:00
|
|
|
/*
|
|
|
|
* resize2fs.c --- ext2 main routine
|
|
|
|
*
|
2000-04-07 01:38:34 +04:00
|
|
|
* Copyright (C) 1997, 1998 by Theodore Ts'o and
|
|
|
|
* PowerQuest, Inc.
|
|
|
|
*
|
|
|
|
* Copyright (C) 1999, 2000 by Theosore Ts'o
|
2008-08-28 07:07:54 +04:00
|
|
|
*
|
1997-06-08 00:42:58 +04:00
|
|
|
* %Begin-Header%
|
2000-04-07 01:38:34 +04:00
|
|
|
* This file may be redistributed under the terms of the GNU Public
|
|
|
|
* License.
|
1997-06-08 00:42:58 +04:00
|
|
|
* %End-Header%
|
|
|
|
*/
|
|
|
|
|
1997-06-14 11:28:44 +04:00
|
|
|
/*
|
|
|
|
* Resizing a filesystem consists of the following phases:
|
|
|
|
*
|
1998-02-17 01:16:20 +03:00
|
|
|
* 1. Adjust superblock and write out new parts of the inode
|
1997-06-14 11:28:44 +04:00
|
|
|
* table
|
1998-02-17 01:16:20 +03:00
|
|
|
* 2. Determine blocks which need to be relocated, and copy the
|
|
|
|
* contents of blocks from their old locations to the new ones.
|
|
|
|
* 3. Scan the inode table, doing the following:
|
|
|
|
* a. If blocks have been moved, update the block
|
|
|
|
* pointers in the inodes and indirect blocks to
|
|
|
|
* point at the new block locations.
|
|
|
|
* b. If parts of the inode table need to be evacuated,
|
|
|
|
* copy inodes from their old locations to their
|
|
|
|
* new ones.
|
|
|
|
* c. If (b) needs to be done, note which blocks contain
|
|
|
|
* directory information, since we will need to
|
|
|
|
* update the directory information.
|
|
|
|
* 4. Update the directory blocks with the new inode locations.
|
|
|
|
* 5. Move the inode tables, if necessary.
|
1997-06-14 11:28:44 +04:00
|
|
|
*/
|
1998-02-17 01:16:20 +03:00
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
#include "resize2fs.h"
|
2003-12-28 15:04:35 +03:00
|
|
|
#include <time.h>
|
1997-06-08 00:42:58 +04:00
|
|
|
|
2002-03-08 07:52:56 +03:00
|
|
|
#ifdef __linux__ /* Kludge for debugging */
|
1998-02-17 01:16:20 +03:00
|
|
|
#define RESIZE2FS_DEBUG
|
|
|
|
#endif
|
|
|
|
|
2008-08-22 11:03:42 +04:00
|
|
|
static void fix_uninit_block_bitmaps(ext2_filsys fs);
|
1998-02-17 01:16:20 +03:00
|
|
|
static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size);
|
|
|
|
static errcode_t blocks_to_move(ext2_resize_t rfs);
|
|
|
|
static errcode_t block_mover(ext2_resize_t rfs);
|
|
|
|
static errcode_t inode_scan_and_fix(ext2_resize_t rfs);
|
|
|
|
static errcode_t inode_ref_fix(ext2_resize_t rfs);
|
|
|
|
static errcode_t move_itables(ext2_resize_t rfs);
|
2004-12-24 09:34:29 +03:00
|
|
|
static errcode_t fix_resize_inode(ext2_filsys fs);
|
1998-02-17 01:16:20 +03:00
|
|
|
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Some helper CPP macros
|
|
|
|
*/
|
|
|
|
#define FS_BLOCK_BM(fs, i) ((fs)->group_desc[(i)].bg_block_bitmap)
|
|
|
|
#define FS_INODE_BM(fs, i) ((fs)->group_desc[(i)].bg_inode_bitmap)
|
|
|
|
#define FS_INODE_TB(fs, i) ((fs)->group_desc[(i)].bg_inode_table)
|
|
|
|
|
|
|
|
#define IS_BLOCK_BM(fs, i, blk) ((blk) == FS_BLOCK_BM((fs),(i)))
|
|
|
|
#define IS_INODE_BM(fs, i, blk) ((blk) == FS_INODE_BM((fs),(i)))
|
|
|
|
|
|
|
|
#define IS_INODE_TB(fs, i, blk) (((blk) >= FS_INODE_TB((fs), (i))) && \
|
|
|
|
((blk) < (FS_INODE_TB((fs), (i)) + \
|
|
|
|
(fs)->inode_blocks_per_group)))
|
|
|
|
|
2008-03-13 20:46:10 +03:00
|
|
|
#define META_OVERHEAD(fs) (2 + (fs)->inode_blocks_per_group)
|
|
|
|
#define SUPER_OVERHEAD(fs) (1 + (fs)->desc_blocks +\
|
|
|
|
(fs)->super->s_reserved_gdt_blocks)
|
1998-02-17 01:16:20 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This is the top-level routine which does the dirty deed....
|
|
|
|
*/
|
2002-04-01 10:28:30 +04:00
|
|
|
errcode_t resize_fs(ext2_filsys fs, blk_t *new_size, int flags,
|
1998-02-24 23:24:49 +03:00
|
|
|
errcode_t (*progress)(ext2_resize_t rfs, int pass,
|
2008-08-22 11:03:42 +04:00
|
|
|
unsigned long cur,
|
|
|
|
unsigned long max_val))
|
1998-02-17 01:16:20 +03:00
|
|
|
{
|
|
|
|
ext2_resize_t rfs;
|
|
|
|
errcode_t retval;
|
|
|
|
|
|
|
|
retval = ext2fs_read_bitmaps(fs);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* Create the data structure
|
|
|
|
*/
|
2003-08-01 17:41:07 +04:00
|
|
|
retval = ext2fs_get_mem(sizeof(struct ext2_resize_struct), &rfs);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
memset(rfs, 0, sizeof(struct ext2_resize_struct));
|
|
|
|
|
2008-08-22 11:03:42 +04:00
|
|
|
fix_uninit_block_bitmaps(fs);
|
2008-08-22 11:07:53 +04:00
|
|
|
fs->priv_data = rfs;
|
1998-02-17 01:16:20 +03:00
|
|
|
rfs->old_fs = fs;
|
|
|
|
rfs->flags = flags;
|
|
|
|
rfs->itable_buf = 0;
|
|
|
|
rfs->progress = progress;
|
|
|
|
retval = ext2fs_dup_handle(fs, &rfs->new_fs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
2002-04-01 10:28:30 +04:00
|
|
|
retval = adjust_superblock(rfs, *new_size);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
2008-08-22 11:03:42 +04:00
|
|
|
fix_uninit_block_bitmaps(rfs->new_fs);
|
|
|
|
/* Clear the block bitmap uninit flag for the last block group */
|
|
|
|
rfs->new_fs->group_desc[rfs->new_fs->group_desc_count-1].bg_flags &=
|
|
|
|
~EXT2_BG_BLOCK_UNINIT;
|
|
|
|
|
2002-04-01 10:28:30 +04:00
|
|
|
*new_size = rfs->new_fs->super->s_blocks_count;
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = blocks_to_move(rfs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (rfs->flags & RESIZE_DEBUG_BMOVE)
|
2006-03-19 05:43:46 +03:00
|
|
|
printf("Number of free blocks: %u/%u, Needed: %d\n",
|
1998-02-17 01:16:20 +03:00
|
|
|
rfs->old_fs->super->s_free_blocks_count,
|
|
|
|
rfs->new_fs->super->s_free_blocks_count,
|
|
|
|
rfs->needed_blocks);
|
|
|
|
#endif
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = block_mover(rfs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
retval = inode_scan_and_fix(rfs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
retval = inode_ref_fix(rfs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
retval = move_itables(rfs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
2005-01-26 18:03:56 +03:00
|
|
|
retval = ext2fs_calculate_summary_stats(rfs->new_fs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2004-12-24 09:34:29 +03:00
|
|
|
retval = fix_resize_inode(rfs->new_fs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
2008-08-28 07:07:54 +04:00
|
|
|
rfs->new_fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = ext2fs_close(rfs->new_fs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
rfs->flags = flags;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_free(rfs->old_fs);
|
|
|
|
if (rfs->itable_buf)
|
2003-08-01 17:41:07 +04:00
|
|
|
ext2fs_free_mem(&rfs->itable_buf);
|
|
|
|
ext2fs_free_mem(&rfs);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
if (rfs->new_fs)
|
|
|
|
ext2fs_free(rfs->new_fs);
|
|
|
|
if (rfs->itable_buf)
|
2003-08-01 17:41:07 +04:00
|
|
|
ext2fs_free_mem(&rfs->itable_buf);
|
|
|
|
ext2fs_free_mem(&rfs);
|
1998-02-17 01:16:20 +03:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2008-08-22 11:03:42 +04:00
|
|
|
/*
|
|
|
|
* Clean up the bitmaps for unitialized bitmaps
|
|
|
|
*/
|
|
|
|
static void fix_uninit_block_bitmaps(ext2_filsys fs)
|
|
|
|
{
|
2008-11-16 18:03:00 +03:00
|
|
|
blk_t i, blk, super_blk, old_desc_blk, new_desc_blk;
|
2008-08-22 11:03:42 +04:00
|
|
|
int old_desc_blocks;
|
|
|
|
dgrp_t g;
|
|
|
|
|
|
|
|
if (!(EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_GDT_CSUM)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (g=0; g < fs->group_desc_count; g++) {
|
|
|
|
if (!(fs->group_desc[g].bg_flags & EXT2_BG_BLOCK_UNINIT))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
blk = (g * fs->super->s_blocks_per_group) +
|
|
|
|
fs->super->s_first_data_block;
|
|
|
|
|
|
|
|
ext2fs_super_and_bgd_loc(fs, g, &super_blk,
|
|
|
|
&old_desc_blk, &new_desc_blk, 0);
|
|
|
|
|
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
old_desc_blocks = fs->super->s_first_meta_bg;
|
|
|
|
else
|
2008-08-28 07:07:54 +04:00
|
|
|
old_desc_blocks = fs->desc_blocks +
|
2008-08-22 11:03:42 +04:00
|
|
|
fs->super->s_reserved_gdt_blocks;
|
|
|
|
|
|
|
|
for (i=0; i < fs->super->s_blocks_per_group; i++, blk++) {
|
|
|
|
if (blk >= fs->super->s_blocks_count)
|
|
|
|
break;
|
|
|
|
if ((blk == super_blk) ||
|
|
|
|
(old_desc_blk && old_desc_blocks &&
|
|
|
|
(blk >= old_desc_blk) &&
|
|
|
|
(blk < old_desc_blk + old_desc_blocks)) ||
|
|
|
|
(new_desc_blk && (blk == new_desc_blk)) ||
|
|
|
|
(blk == fs->group_desc[g].bg_block_bitmap) ||
|
|
|
|
(blk == fs->group_desc[g].bg_inode_bitmap) ||
|
|
|
|
(blk >= fs->group_desc[g].bg_inode_table &&
|
|
|
|
(blk < fs->group_desc[g].bg_inode_table
|
|
|
|
+ fs->inode_blocks_per_group)))
|
|
|
|
ext2fs_fast_mark_block_bitmap(fs->block_map, blk);
|
|
|
|
else
|
|
|
|
ext2fs_fast_unmark_block_bitmap(fs->block_map, blk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/* --------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Resize processing, phase 1.
|
|
|
|
*
|
|
|
|
* In this phase we adjust the in-memory superblock information, and
|
|
|
|
* initialize any new parts of the inode table. The new parts of the
|
|
|
|
* inode table are created in virgin disk space, so we can abort here
|
|
|
|
* without any side effects.
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
2009-01-19 17:02:55 +03:00
|
|
|
/*
|
|
|
|
* If the group descriptor's bitmap and inode table blocks are valid,
|
|
|
|
* release them in the specified filesystem data structure
|
|
|
|
*/
|
|
|
|
static void free_gdp_blocks(ext2_filsys fs, struct ext2_group_desc *gdp)
|
|
|
|
{
|
|
|
|
blk_t blk;
|
|
|
|
int j;
|
|
|
|
|
|
|
|
if (gdp->bg_block_bitmap &&
|
|
|
|
(gdp->bg_block_bitmap < fs->super->s_blocks_count))
|
|
|
|
ext2fs_block_alloc_stats(fs, gdp->bg_block_bitmap, -1);
|
|
|
|
|
|
|
|
if (gdp->bg_inode_bitmap &&
|
|
|
|
(gdp->bg_inode_bitmap < fs->super->s_blocks_count))
|
|
|
|
ext2fs_block_alloc_stats(fs, gdp->bg_inode_bitmap, -1);
|
|
|
|
|
|
|
|
if (gdp->bg_inode_table == 0 ||
|
|
|
|
(gdp->bg_inode_table >= fs->super->s_blocks_count))
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (blk = gdp->bg_inode_table, j = 0;
|
|
|
|
j < fs->inode_blocks_per_group; j++, blk++) {
|
|
|
|
if (blk >= fs->super->s_blocks_count)
|
|
|
|
break;
|
|
|
|
ext2fs_block_alloc_stats(fs, blk, -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
/*
|
2006-03-18 03:45:45 +03:00
|
|
|
* This routine is shared by the online and offline resize routines.
|
|
|
|
* All of the information which is adjusted in memory is done here.
|
1997-06-08 00:42:58 +04:00
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
errcode_t adjust_fs_info(ext2_filsys fs, ext2_filsys old_fs, blk_t new_size)
|
1997-06-08 00:42:58 +04:00
|
|
|
{
|
|
|
|
errcode_t retval;
|
2006-03-18 03:45:45 +03:00
|
|
|
int overhead = 0;
|
|
|
|
int rem;
|
1997-06-08 00:42:58 +04:00
|
|
|
blk_t blk, group_block;
|
2006-03-18 03:45:45 +03:00
|
|
|
ext2_ino_t real_end;
|
|
|
|
int adj, old_numblocks, numblocks, adjblocks;
|
|
|
|
unsigned long i, j, old_desc_blocks, max_group;
|
2003-12-07 09:28:50 +03:00
|
|
|
unsigned int meta_bg, meta_bg_size;
|
2008-06-17 06:13:55 +04:00
|
|
|
int has_super, csum_flag;
|
2007-05-25 19:18:11 +04:00
|
|
|
unsigned long long new_inodes; /* u64 to check for overflow */
|
2008-06-18 03:58:29 +04:00
|
|
|
double percent;
|
2006-03-18 03:45:45 +03:00
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
fs->super->s_blocks_count = new_size;
|
|
|
|
|
|
|
|
retry:
|
2006-08-30 09:57:00 +04:00
|
|
|
fs->group_desc_count = ext2fs_div_ceil(fs->super->s_blocks_count -
|
|
|
|
fs->super->s_first_data_block,
|
|
|
|
EXT2_BLOCKS_PER_GROUP(fs->super));
|
1997-06-08 00:42:58 +04:00
|
|
|
if (fs->group_desc_count == 0)
|
|
|
|
return EXT2_ET_TOOSMALL;
|
2008-08-28 07:07:54 +04:00
|
|
|
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
|
2006-08-30 09:57:00 +04:00
|
|
|
EXT2_DESC_PER_BLOCK(fs->super));
|
1997-06-08 00:42:58 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Overhead is the number of bookkeeping blocks per group. It
|
|
|
|
* includes the superblock backup, the group descriptor
|
|
|
|
* backups, the inode bitmap, the block bitmap, and the inode
|
|
|
|
* table.
|
|
|
|
*/
|
2004-12-24 09:34:29 +03:00
|
|
|
overhead = (int) (2 + fs->inode_blocks_per_group);
|
|
|
|
|
|
|
|
if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
|
2008-08-28 07:07:54 +04:00
|
|
|
overhead += 1 + fs->desc_blocks +
|
2004-12-24 09:34:29 +03:00
|
|
|
fs->super->s_reserved_gdt_blocks;
|
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
/*
|
|
|
|
* See if the last group is big enough to support the
|
|
|
|
* necessary data structures. If not, we need to get rid of
|
|
|
|
* it.
|
|
|
|
*/
|
|
|
|
rem = (fs->super->s_blocks_count - fs->super->s_first_data_block) %
|
|
|
|
fs->super->s_blocks_per_group;
|
|
|
|
if ((fs->group_desc_count == 1) && rem && (rem < overhead))
|
|
|
|
return EXT2_ET_TOOSMALL;
|
|
|
|
if (rem && (rem < overhead+50)) {
|
|
|
|
fs->super->s_blocks_count -= rem;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Adjust the number of inodes
|
|
|
|
*/
|
2007-05-25 19:18:11 +04:00
|
|
|
new_inodes =(unsigned long long) fs->super->s_inodes_per_group * fs->group_desc_count;
|
2006-09-12 22:56:17 +04:00
|
|
|
if (new_inodes > ~0U) {
|
|
|
|
fprintf(stderr, _("inodes (%llu) must be less than %u"),
|
|
|
|
new_inodes, ~0U);
|
|
|
|
return EXT2_ET_TOO_MANY_INODES;
|
|
|
|
}
|
1997-06-08 00:42:58 +04:00
|
|
|
fs->super->s_inodes_count = fs->super->s_inodes_per_group *
|
|
|
|
fs->group_desc_count;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Adjust the number of free blocks
|
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
blk = old_fs->super->s_blocks_count;
|
1997-06-08 00:42:58 +04:00
|
|
|
if (blk > fs->super->s_blocks_count)
|
|
|
|
fs->super->s_free_blocks_count -=
|
|
|
|
(blk - fs->super->s_blocks_count);
|
|
|
|
else
|
|
|
|
fs->super->s_free_blocks_count +=
|
|
|
|
(fs->super->s_blocks_count - blk);
|
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
|
|
|
* Adjust the number of reserved blocks
|
|
|
|
*/
|
2008-06-18 03:58:29 +04:00
|
|
|
percent = (old_fs->super->s_r_blocks_count * 100.0) /
|
2006-03-18 03:45:45 +03:00
|
|
|
old_fs->super->s_blocks_count;
|
2008-06-18 03:58:29 +04:00
|
|
|
fs->super->s_r_blocks_count = (unsigned int) (percent *
|
|
|
|
fs->super->s_blocks_count / 100.0);
|
1997-06-17 07:52:12 +04:00
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
/*
|
|
|
|
* Adjust the bitmaps for size
|
|
|
|
*/
|
|
|
|
retval = ext2fs_resize_inode_bitmap(fs->super->s_inodes_count,
|
|
|
|
fs->super->s_inodes_count,
|
|
|
|
fs->inode_map);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (retval) goto errout;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
real_end = ((EXT2_BLOCKS_PER_GROUP(fs->super)
|
|
|
|
* fs->group_desc_count)) - 1 +
|
|
|
|
fs->super->s_first_data_block;
|
|
|
|
retval = ext2fs_resize_block_bitmap(fs->super->s_blocks_count-1,
|
|
|
|
real_end, fs->block_map);
|
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
if (retval) goto errout;
|
1997-06-08 00:42:58 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reallocate the group descriptors as necessary.
|
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
if (old_fs->desc_blocks != fs->desc_blocks) {
|
|
|
|
retval = ext2fs_resize_mem(old_fs->desc_blocks *
|
1998-04-27 05:41:13 +04:00
|
|
|
fs->blocksize,
|
|
|
|
fs->desc_blocks * fs->blocksize,
|
2003-08-01 17:41:07 +04:00
|
|
|
&fs->group_desc);
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
if (retval)
|
1998-02-17 01:16:20 +03:00
|
|
|
goto errout;
|
2008-08-28 07:07:54 +04:00
|
|
|
if (fs->desc_blocks > old_fs->desc_blocks)
|
|
|
|
memset((char *) fs->group_desc +
|
2006-03-18 03:45:45 +03:00
|
|
|
(old_fs->desc_blocks * fs->blocksize), 0,
|
|
|
|
(fs->desc_blocks - old_fs->desc_blocks) *
|
2005-08-09 03:57:04 +04:00
|
|
|
fs->blocksize);
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
|
2004-12-24 09:34:29 +03:00
|
|
|
/*
|
|
|
|
* If the resize_inode feature is set, and we are changing the
|
|
|
|
* number of descriptor blocks, then adjust
|
|
|
|
* s_reserved_gdt_blocks if possible to avoid needing to move
|
|
|
|
* the inode table either now or in the future.
|
|
|
|
*/
|
2008-08-28 07:07:54 +04:00
|
|
|
if ((fs->super->s_feature_compat &
|
2004-12-24 09:34:29 +03:00
|
|
|
EXT2_FEATURE_COMPAT_RESIZE_INODE) &&
|
2006-03-18 03:45:45 +03:00
|
|
|
(old_fs->desc_blocks != fs->desc_blocks)) {
|
2004-12-24 09:34:29 +03:00
|
|
|
int new;
|
|
|
|
|
2008-08-28 07:07:54 +04:00
|
|
|
new = ((int) fs->super->s_reserved_gdt_blocks) +
|
2006-03-18 03:45:45 +03:00
|
|
|
(old_fs->desc_blocks - fs->desc_blocks);
|
2004-12-24 09:34:29 +03:00
|
|
|
if (new < 0)
|
|
|
|
new = 0;
|
2007-05-25 19:18:11 +04:00
|
|
|
if (new > (int) fs->blocksize/4)
|
2004-12-24 09:34:29 +03:00
|
|
|
new = fs->blocksize/4;
|
|
|
|
fs->super->s_reserved_gdt_blocks = new;
|
|
|
|
}
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* If we are shrinking the number block groups, we're done and
|
|
|
|
* can exit now.
|
1997-06-09 18:51:29 +04:00
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
if (old_fs->group_desc_count > fs->group_desc_count) {
|
2009-01-19 17:02:55 +03:00
|
|
|
/*
|
|
|
|
* Check the block groups that we are chopping off
|
|
|
|
* and free any blocks associated with their metadata
|
|
|
|
*/
|
|
|
|
for (i = fs->group_desc_count;
|
|
|
|
i < old_fs->group_desc_count; i++) {
|
|
|
|
free_gdp_blocks(fs, &old_fs->group_desc[i]);
|
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
2006-03-18 03:45:45 +03:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* Fix the count of the last (old) block group
|
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
old_numblocks = (old_fs->super->s_blocks_count -
|
|
|
|
old_fs->super->s_first_data_block) %
|
|
|
|
old_fs->super->s_blocks_per_group;
|
1997-06-09 18:51:29 +04:00
|
|
|
if (!old_numblocks)
|
2006-03-18 03:45:45 +03:00
|
|
|
old_numblocks = old_fs->super->s_blocks_per_group;
|
|
|
|
if (old_fs->group_desc_count == fs->group_desc_count) {
|
|
|
|
numblocks = (fs->super->s_blocks_count -
|
|
|
|
fs->super->s_first_data_block) %
|
|
|
|
fs->super->s_blocks_per_group;
|
1997-06-09 18:51:29 +04:00
|
|
|
if (!numblocks)
|
2006-03-18 03:45:45 +03:00
|
|
|
numblocks = fs->super->s_blocks_per_group;
|
1997-06-09 18:51:29 +04:00
|
|
|
} else
|
2006-03-18 03:45:45 +03:00
|
|
|
numblocks = fs->super->s_blocks_per_group;
|
|
|
|
i = old_fs->group_desc_count - 1;
|
1997-06-09 18:51:29 +04:00
|
|
|
fs->group_desc[i].bg_free_blocks_count += (numblocks-old_numblocks);
|
2007-10-22 06:03:52 +04:00
|
|
|
ext2fs_group_desc_csum_set(fs, i);
|
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
/*
|
1998-02-17 01:16:20 +03:00
|
|
|
* If the number of block groups is staying the same, we're
|
|
|
|
* done and can exit now. (If the number block groups is
|
|
|
|
* shrinking, we had exited earlier.)
|
1997-06-09 18:51:29 +04:00
|
|
|
*/
|
2006-03-18 03:45:45 +03:00
|
|
|
if (old_fs->group_desc_count >= fs->group_desc_count) {
|
1997-06-17 07:52:12 +04:00
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
2006-03-18 03:45:45 +03:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* Initialize the new block group descriptors
|
|
|
|
*/
|
1997-06-09 18:51:29 +04:00
|
|
|
group_block = fs->super->s_first_data_block +
|
2006-03-18 03:45:45 +03:00
|
|
|
old_fs->group_desc_count * fs->super->s_blocks_per_group;
|
1997-06-17 07:52:12 +04:00
|
|
|
|
2008-06-17 06:13:55 +04:00
|
|
|
csum_flag = EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_GDT_CSUM);
|
2006-03-18 03:45:45 +03:00
|
|
|
adj = old_fs->group_desc_count;
|
1998-02-14 01:58:18 +03:00
|
|
|
max_group = fs->group_desc_count - adj;
|
2002-10-31 07:07:21 +03:00
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
old_desc_blocks = fs->super->s_first_meta_bg;
|
|
|
|
else
|
2008-08-28 07:07:54 +04:00
|
|
|
old_desc_blocks = fs->desc_blocks +
|
2004-12-24 09:34:29 +03:00
|
|
|
fs->super->s_reserved_gdt_blocks;
|
2006-03-18 03:45:45 +03:00
|
|
|
for (i = old_fs->group_desc_count;
|
1997-06-09 18:51:29 +04:00
|
|
|
i < fs->group_desc_count; i++) {
|
|
|
|
memset(&fs->group_desc[i], 0,
|
|
|
|
sizeof(struct ext2_group_desc));
|
|
|
|
adjblocks = 0;
|
|
|
|
|
2008-06-17 06:13:55 +04:00
|
|
|
fs->group_desc[i].bg_flags = 0;
|
|
|
|
if (csum_flag)
|
|
|
|
fs->group_desc[i].bg_flags |= EXT2_BG_INODE_UNINIT |
|
|
|
|
EXT2_BG_INODE_ZEROED;
|
1997-06-09 18:51:29 +04:00
|
|
|
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;
|
2008-06-17 06:13:55 +04:00
|
|
|
} else {
|
1997-06-09 18:51:29 +04:00
|
|
|
numblocks = fs->super->s_blocks_per_group;
|
2008-06-17 06:13:55 +04:00
|
|
|
if (csum_flag)
|
|
|
|
fs->group_desc[i].bg_flags |=
|
|
|
|
EXT2_BG_BLOCK_UNINIT;
|
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
|
2002-10-31 07:07:21 +03:00
|
|
|
has_super = ext2fs_bg_has_super(fs, i);
|
|
|
|
if (has_super) {
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, group_block, +1);
|
2002-10-31 07:07:21 +03:00
|
|
|
adjblocks++;
|
|
|
|
}
|
2007-08-30 19:38:13 +04:00
|
|
|
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
2002-10-31 07:07:21 +03:00
|
|
|
meta_bg = i / meta_bg_size;
|
|
|
|
if (!(fs->super->s_feature_incompat &
|
|
|
|
EXT2_FEATURE_INCOMPAT_META_BG) ||
|
|
|
|
(meta_bg < fs->super->s_first_meta_bg)) {
|
|
|
|
if (has_super) {
|
|
|
|
for (j=0; j < old_desc_blocks; j++)
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs,
|
|
|
|
group_block + 1 + j, +1);
|
2002-10-31 07:07:21 +03:00
|
|
|
adjblocks += old_desc_blocks;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (has_super)
|
|
|
|
has_super = 1;
|
|
|
|
if (((i % meta_bg_size) == 0) ||
|
|
|
|
((i % meta_bg_size) == 1) ||
|
|
|
|
((i % meta_bg_size) == (meta_bg_size-1)))
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs,
|
|
|
|
group_block + has_super, +1);
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
adjblocks += 2 + fs->inode_blocks_per_group;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
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;
|
2007-10-22 06:03:52 +04:00
|
|
|
ext2fs_group_desc_csum_set(fs, i);
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
retval = ext2fs_allocate_group_table(fs, i, 0);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (retval) goto errout;
|
1997-06-08 00:42:58 +04:00
|
|
|
|
2006-03-18 03:45:45 +03:00
|
|
|
group_block += fs->super->s_blocks_per_group;
|
|
|
|
}
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
return (retval);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* This routine adjusts the superblock and other data structures, both
|
|
|
|
* in disk as well as in memory...
|
|
|
|
*/
|
|
|
|
static errcode_t adjust_superblock(ext2_resize_t rfs, blk_t new_size)
|
|
|
|
{
|
|
|
|
ext2_filsys fs;
|
|
|
|
int adj = 0;
|
|
|
|
errcode_t retval;
|
|
|
|
blk_t group_block;
|
|
|
|
unsigned long i;
|
|
|
|
unsigned long max_group;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2006-03-18 03:45:45 +03:00
|
|
|
fs = rfs->new_fs;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
|
|
|
ext2fs_mark_bb_dirty(fs);
|
|
|
|
ext2fs_mark_ib_dirty(fs);
|
|
|
|
|
|
|
|
retval = adjust_fs_info(fs, rfs->old_fs, new_size);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to make sure there are enough inodes
|
|
|
|
*/
|
|
|
|
if ((rfs->old_fs->super->s_inodes_count -
|
|
|
|
rfs->old_fs->super->s_free_inodes_count) >
|
|
|
|
rfs->new_fs->super->s_inodes_count) {
|
|
|
|
retval = ENOSPC;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we are shrinking the number block groups, we're done and
|
|
|
|
* can exit now.
|
|
|
|
*/
|
|
|
|
if (rfs->old_fs->group_desc_count > fs->group_desc_count) {
|
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the number of block groups is staying the same, we're
|
|
|
|
* done and can exit now. (If the number block groups is
|
|
|
|
* shrinking, we had exited earlier.)
|
|
|
|
*/
|
|
|
|
if (rfs->old_fs->group_desc_count >= fs->group_desc_count) {
|
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the new block group descriptors
|
|
|
|
*/
|
2007-12-27 18:08:13 +03:00
|
|
|
retval = ext2fs_get_array(fs->blocksize, fs->inode_blocks_per_group,
|
2006-03-18 03:45:45 +03:00
|
|
|
&rfs->itable_buf);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
memset(rfs->itable_buf, 0, fs->blocksize * fs->inode_blocks_per_group);
|
|
|
|
group_block = fs->super->s_first_data_block +
|
|
|
|
rfs->old_fs->group_desc_count * fs->super->s_blocks_per_group;
|
|
|
|
|
|
|
|
adj = rfs->old_fs->group_desc_count;
|
|
|
|
max_group = fs->group_desc_count - adj;
|
|
|
|
if (rfs->progress) {
|
|
|
|
retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
|
|
|
|
0, max_group);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
for (i = rfs->old_fs->group_desc_count;
|
|
|
|
i < fs->group_desc_count; i++) {
|
1997-06-14 11:28:44 +04:00
|
|
|
/*
|
|
|
|
* Write out the new inode table
|
|
|
|
*/
|
|
|
|
retval = io_channel_write_blk(fs->io,
|
|
|
|
fs->group_desc[i].bg_inode_table,
|
|
|
|
fs->inode_blocks_per_group,
|
|
|
|
rfs->itable_buf);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (retval) goto errout;
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
io_channel_flush(fs->io);
|
1998-02-24 23:24:49 +03:00
|
|
|
if (rfs->progress) {
|
|
|
|
retval = rfs->progress(rfs, E2_RSZ_EXTEND_ITABLE_PASS,
|
|
|
|
i - adj + 1, max_group);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
group_block += fs->super->s_blocks_per_group;
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
io_channel_flush(fs->io);
|
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/* --------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Resize processing, phase 2.
|
|
|
|
*
|
|
|
|
* In this phase we adjust determine which blocks need to be moved, in
|
|
|
|
* blocks_to_move(). We then copy the blocks to their ultimate new
|
|
|
|
* destinations using block_mover(). Since we are copying blocks to
|
|
|
|
* their new locations, again during this pass we can abort without
|
|
|
|
* any problems.
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
|
|
|
* This helper function creates a block bitmap with all of the
|
|
|
|
* filesystem meta-data blocks.
|
|
|
|
*/
|
|
|
|
static errcode_t mark_table_blocks(ext2_filsys fs,
|
2005-01-26 18:03:56 +03:00
|
|
|
ext2fs_block_bitmap bmap)
|
1997-06-17 07:52:12 +04:00
|
|
|
{
|
2006-09-12 22:56:12 +04:00
|
|
|
blk_t b;
|
2003-12-07 09:28:50 +03:00
|
|
|
unsigned int j;
|
|
|
|
dgrp_t i;
|
2005-12-29 23:44:45 +03:00
|
|
|
unsigned long meta_bg_size;
|
2003-12-07 09:28:50 +03:00
|
|
|
unsigned int old_desc_blocks;
|
1997-06-17 07:52:12 +04:00
|
|
|
|
2007-08-30 19:38:13 +04:00
|
|
|
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
2002-10-31 07:07:21 +03:00
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
old_desc_blocks = fs->super->s_first_meta_bg;
|
|
|
|
else
|
2008-08-28 07:07:54 +04:00
|
|
|
old_desc_blocks = fs->desc_blocks +
|
2004-12-24 09:34:29 +03:00
|
|
|
fs->super->s_reserved_gdt_blocks;
|
1997-06-17 07:52:12 +04:00
|
|
|
for (i = 0; i < fs->group_desc_count; i++) {
|
2005-01-26 18:03:56 +03:00
|
|
|
ext2fs_reserve_super_and_bgd(fs, i, bmap);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
|
|
|
* Mark the blocks used for the inode table
|
|
|
|
*/
|
|
|
|
for (j = 0, b = fs->group_desc[i].bg_inode_table;
|
2003-12-07 09:28:50 +03:00
|
|
|
j < (unsigned int) fs->inode_blocks_per_group;
|
1997-06-17 07:52:12 +04:00
|
|
|
j++, b++)
|
|
|
|
ext2fs_mark_block_bitmap(bmap, b);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
2008-08-28 07:07:54 +04:00
|
|
|
* Mark block used for the block bitmap
|
1997-06-17 07:52:12 +04:00
|
|
|
*/
|
|
|
|
ext2fs_mark_block_bitmap(bmap,
|
|
|
|
fs->group_desc[i].bg_block_bitmap);
|
2005-01-26 18:03:56 +03:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
2008-08-28 07:07:54 +04:00
|
|
|
* Mark block used for the inode bitmap
|
1997-06-17 07:52:12 +04:00
|
|
|
*/
|
|
|
|
ext2fs_mark_block_bitmap(bmap,
|
|
|
|
fs->group_desc[i].bg_inode_bitmap);
|
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
return 0;
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
|
|
|
|
2002-10-31 07:07:21 +03:00
|
|
|
/*
|
|
|
|
* This function checks to see if a particular block (either a
|
|
|
|
* superblock or a block group descriptor) overlaps with an inode or
|
|
|
|
* block bitmap block, or with the inode table.
|
|
|
|
*/
|
|
|
|
static void mark_fs_metablock(ext2_resize_t rfs,
|
|
|
|
ext2fs_block_bitmap meta_bmap,
|
|
|
|
int group, blk_t blk)
|
|
|
|
{
|
|
|
|
ext2_filsys fs = rfs->new_fs;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2002-10-31 07:07:21 +03:00
|
|
|
ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, +1);
|
2002-10-31 07:07:21 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check to see if we overlap with the inode or block bitmap,
|
|
|
|
* or the inode tables. If not, and the block is in use, then
|
|
|
|
* mark it as a block to be moved.
|
|
|
|
*/
|
|
|
|
if (IS_BLOCK_BM(fs, group, blk)) {
|
|
|
|
FS_BLOCK_BM(fs, group) = 0;
|
|
|
|
rfs->needed_blocks++;
|
|
|
|
} else if (IS_INODE_BM(fs, group, blk)) {
|
|
|
|
FS_INODE_BM(fs, group) = 0;
|
|
|
|
rfs->needed_blocks++;
|
|
|
|
} else if (IS_INODE_TB(fs, group, blk)) {
|
|
|
|
FS_INODE_TB(fs, group) = 0;
|
|
|
|
rfs->needed_blocks++;
|
2008-08-22 11:03:42 +04:00
|
|
|
} else if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
|
|
|
|
(fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT)) {
|
|
|
|
/*
|
|
|
|
* If the block bitmap is uninitialized, which means
|
|
|
|
* nothing other than standard metadata in use.
|
|
|
|
*/
|
|
|
|
return;
|
2002-10-31 07:07:21 +03:00
|
|
|
} else if (ext2fs_test_block_bitmap(rfs->old_fs->block_map, blk) &&
|
|
|
|
!ext2fs_test_block_bitmap(meta_bmap, blk)) {
|
|
|
|
ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
|
|
|
|
rfs->needed_blocks++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
/*
|
|
|
|
* This routine marks and unmarks reserved blocks in the new block
|
|
|
|
* bitmap. It also determines which blocks need to be moved and
|
|
|
|
* places this information into the move_blocks bitmap.
|
|
|
|
*/
|
1997-06-17 07:52:12 +04:00
|
|
|
static errcode_t blocks_to_move(ext2_resize_t rfs)
|
1997-06-08 00:42:58 +04:00
|
|
|
{
|
2003-12-07 09:28:50 +03:00
|
|
|
int j, has_super;
|
2008-08-22 11:03:42 +04:00
|
|
|
dgrp_t i, max_groups, g;
|
2003-12-07 09:28:50 +03:00
|
|
|
blk_t blk, group_blk;
|
|
|
|
unsigned long old_blocks, new_blocks;
|
|
|
|
unsigned int meta_bg, meta_bg_size;
|
1997-06-08 00:42:58 +04:00
|
|
|
errcode_t retval;
|
1997-06-17 07:52:12 +04:00
|
|
|
ext2_filsys fs, old_fs;
|
|
|
|
ext2fs_block_bitmap meta_bmap;
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
fs = rfs->new_fs;
|
|
|
|
old_fs = rfs->old_fs;
|
|
|
|
if (old_fs->super->s_blocks_count > fs->super->s_blocks_count)
|
|
|
|
fs = rfs->old_fs;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2000-06-13 02:06:16 +04:00
|
|
|
retval = ext2fs_allocate_block_bitmap(fs, _("reserved blocks"),
|
1997-06-09 18:51:29 +04:00
|
|
|
&rfs->reserve_blocks);
|
1997-06-08 00:42:58 +04:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
1997-06-09 18:51:29 +04:00
|
|
|
|
2000-06-13 02:06:16 +04:00
|
|
|
retval = ext2fs_allocate_block_bitmap(fs, _("blocks to be moved"),
|
1997-06-17 07:52:12 +04:00
|
|
|
&rfs->move_blocks);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
2008-08-28 07:07:54 +04:00
|
|
|
retval = ext2fs_allocate_block_bitmap(fs, _("meta-data blocks"),
|
2005-01-26 18:03:56 +03:00
|
|
|
&meta_bmap);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2005-01-26 18:03:56 +03:00
|
|
|
retval = mark_table_blocks(old_fs, meta_bmap);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
fs = rfs->new_fs;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
/*
|
|
|
|
* 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;
|
1997-06-17 07:52:12 +04:00
|
|
|
blk < old_fs->super->s_blocks_count; blk++) {
|
2008-08-22 11:03:42 +04:00
|
|
|
g = ext2fs_group_of_blk(fs, blk);
|
|
|
|
if (EXT2_HAS_RO_COMPAT_FEATURE(fs->super,
|
|
|
|
EXT4_FEATURE_RO_COMPAT_GDT_CSUM) &&
|
resize2fs: Move all required blocks for ext4 filesystems
In the function blocks_to_move(), when checking to see if a block
group's block bitmap is initialized, we need to check the old_fs's
block group descriptors, not the new file system's (already truncated)
group descriptor data structures. Otherwise we will end up
derferencing past the end of the array boundary, and the resulting
garbage value may indicate that the bitmap is uninitialized, and so
all of the blocks in that block group will be skipped, resulting in
some blocks not getting marked as needing relocation.
This showed up in the following test case:
mke2fs -t ext4 -b 1024 test.img 1048576
resize2fs test.img 80000
The journal inode after the resize operation looked like this:
debugfs: stat <8>
Inode: 8 Type: regular Mode: 0600 Flags: 0x80000
...
BLOCKS:
(IND):35385, (0-5836):2356-8192, (5837-21959):8454-24576, (21960-32506):24838-35
384, (32507-32767):434177-434437
TOTAL: 32769
The blocks 434177-434437 were not moved because block group 53 was
wrongly thought to have an unitialized block group.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2009-01-19 16:43:36 +03:00
|
|
|
(old_fs->group_desc[g].bg_flags & EXT2_BG_BLOCK_UNINIT)) {
|
2008-08-22 11:03:42 +04:00
|
|
|
/*
|
|
|
|
* The block bitmap is uninitialized, so skip
|
|
|
|
* to the next block group.
|
|
|
|
*/
|
|
|
|
blk = ((g+1) * fs->super->s_blocks_per_group) +
|
|
|
|
fs->super->s_first_data_block;
|
|
|
|
continue;
|
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
|
|
|
|
!ext2fs_test_block_bitmap(meta_bmap, blk)) {
|
|
|
|
ext2fs_mark_block_bitmap(rfs->move_blocks, blk);
|
1997-06-09 18:51:29 +04:00
|
|
|
rfs->needed_blocks++;
|
1997-06-17 07:52:12 +04:00
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
ext2fs_mark_block_bitmap(rfs->reserve_blocks, blk);
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2002-10-31 07:07:21 +03:00
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG) {
|
|
|
|
old_blocks = old_fs->super->s_first_meta_bg;
|
|
|
|
new_blocks = fs->super->s_first_meta_bg;
|
|
|
|
} else {
|
2004-12-24 09:34:29 +03:00
|
|
|
old_blocks = old_fs->desc_blocks + old_fs->super->s_reserved_gdt_blocks;
|
|
|
|
new_blocks = fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
|
2002-10-31 07:07:21 +03:00
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
if (old_blocks == new_blocks) {
|
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1998-09-03 04:26:49 +04:00
|
|
|
max_groups = fs->group_desc_count;
|
|
|
|
if (max_groups > old_fs->group_desc_count)
|
|
|
|
max_groups = old_fs->group_desc_count;
|
1997-06-17 07:52:12 +04:00
|
|
|
group_blk = old_fs->super->s_first_data_block;
|
1997-06-08 00:42:58 +04:00
|
|
|
/*
|
|
|
|
* If we're reducing the number of descriptor blocks, this
|
|
|
|
* makes life easy. :-) We just have to mark some extra
|
|
|
|
* blocks as free.
|
|
|
|
*/
|
|
|
|
if (old_blocks > new_blocks) {
|
1998-09-03 04:26:49 +04:00
|
|
|
for (i = 0; i < max_groups; i++) {
|
1997-06-09 18:51:29 +04:00
|
|
|
if (!ext2fs_bg_has_super(fs, i)) {
|
|
|
|
group_blk += fs->super->s_blocks_per_group;
|
1997-06-08 00:42:58 +04:00
|
|
|
continue;
|
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
for (blk = group_blk+1+new_blocks;
|
|
|
|
blk < group_blk+1+old_blocks; blk++) {
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, -1);
|
1997-06-12 11:14:32 +04:00
|
|
|
rfs->needed_blocks--;
|
|
|
|
}
|
1997-06-09 18:51:29 +04:00
|
|
|
group_blk += fs->super->s_blocks_per_group;
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we're increasing the number of descriptor blocks, life
|
2008-08-28 07:07:54 +04:00
|
|
|
* gets interesting....
|
1997-06-08 00:42:58 +04:00
|
|
|
*/
|
2007-08-30 19:38:13 +04:00
|
|
|
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
1998-09-03 04:26:49 +04:00
|
|
|
for (i = 0; i < max_groups; i++) {
|
2002-10-31 07:07:21 +03:00
|
|
|
has_super = ext2fs_bg_has_super(fs, i);
|
|
|
|
if (has_super)
|
|
|
|
mark_fs_metablock(rfs, meta_bmap, i, group_blk);
|
|
|
|
|
|
|
|
meta_bg = i / meta_bg_size;
|
|
|
|
if (!(fs->super->s_feature_incompat &
|
|
|
|
EXT2_FEATURE_INCOMPAT_META_BG) ||
|
|
|
|
(meta_bg < fs->super->s_first_meta_bg)) {
|
2003-03-06 20:22:52 +03:00
|
|
|
if (has_super) {
|
|
|
|
for (blk = group_blk+1;
|
|
|
|
blk < group_blk + 1 + new_blocks; blk++)
|
2008-08-28 07:07:54 +04:00
|
|
|
mark_fs_metablock(rfs, meta_bmap,
|
2003-03-06 20:22:52 +03:00
|
|
|
i, blk);
|
|
|
|
}
|
2002-10-31 07:07:21 +03:00
|
|
|
} else {
|
|
|
|
if (has_super)
|
|
|
|
has_super = 1;
|
|
|
|
if (((i % meta_bg_size) == 0) ||
|
|
|
|
((i % meta_bg_size) == 1) ||
|
|
|
|
((i % meta_bg_size) == (meta_bg_size-1)))
|
|
|
|
mark_fs_metablock(rfs, meta_bmap, i,
|
|
|
|
group_blk + has_super);
|
1997-06-08 00:42:58 +04:00
|
|
|
}
|
2002-10-31 07:07:21 +03:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
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;
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
/*
|
1997-06-17 07:52:12 +04:00
|
|
|
* Reserve the existing meta blocks that we know
|
|
|
|
* aren't to be moved.
|
1997-06-09 18:51:29 +04:00
|
|
|
*/
|
|
|
|
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);
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
/*
|
|
|
|
* Allocate the missing data structures
|
|
|
|
*/
|
1997-06-09 18:51:29 +04:00
|
|
|
retval = ext2fs_allocate_group_table(fs, i,
|
|
|
|
rfs->reserve_blocks);
|
|
|
|
if (retval)
|
1997-06-17 07:52:12 +04:00
|
|
|
goto errout;
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
/*
|
1997-06-17 07:52:12 +04:00
|
|
|
* For those structures that have changed, we need to
|
|
|
|
* do bookkeepping.
|
1997-06-09 18:51:29 +04:00
|
|
|
*/
|
1997-06-17 07:52:12 +04:00
|
|
|
if (FS_BLOCK_BM(old_fs, i) !=
|
|
|
|
(blk = FS_BLOCK_BM(fs, i))) {
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, +1);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
|
|
|
|
!ext2fs_test_block_bitmap(meta_bmap, blk))
|
|
|
|
ext2fs_mark_block_bitmap(rfs->move_blocks,
|
|
|
|
blk);
|
|
|
|
}
|
|
|
|
if (FS_INODE_BM(old_fs, i) !=
|
|
|
|
(blk = FS_INODE_BM(fs, i))) {
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, +1);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
|
|
|
|
!ext2fs_test_block_bitmap(meta_bmap, blk))
|
|
|
|
ext2fs_mark_block_bitmap(rfs->move_blocks,
|
|
|
|
blk);
|
|
|
|
}
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-12 11:14:32 +04:00
|
|
|
/*
|
|
|
|
* The inode table, if we need to relocate it, is
|
|
|
|
* handled specially. We have to reserve the blocks
|
|
|
|
* for both the old and the new inode table, since we
|
|
|
|
* can't have the inode table be destroyed during the
|
|
|
|
* block relocation phase.
|
|
|
|
*/
|
1997-06-17 07:52:12 +04:00
|
|
|
if (FS_INODE_TB(fs, i) == FS_INODE_TB(old_fs, i))
|
1997-06-12 11:14:32 +04:00
|
|
|
goto next_group; /* inode table not moved */
|
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
rfs->needed_blocks += fs->inode_blocks_per_group;
|
1997-06-12 11:14:32 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark the new inode table as in use in the new block
|
2008-08-28 07:07:54 +04:00
|
|
|
* allocation bitmap, and move any blocks that might
|
1997-06-17 07:52:12 +04:00
|
|
|
* be necessary.
|
1997-06-12 11:14:32 +04:00
|
|
|
*/
|
1997-06-09 18:51:29 +04:00
|
|
|
for (blk = fs->group_desc[i].bg_inode_table, j=0;
|
1997-06-17 07:52:12 +04:00
|
|
|
j < fs->inode_blocks_per_group ; j++, blk++) {
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, +1);
|
1997-06-17 07:52:12 +04:00
|
|
|
if (ext2fs_test_block_bitmap(old_fs->block_map, blk) &&
|
|
|
|
!ext2fs_test_block_bitmap(meta_bmap, blk))
|
|
|
|
ext2fs_mark_block_bitmap(rfs->move_blocks,
|
|
|
|
blk);
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
/*
|
1997-06-12 11:14:32 +04:00
|
|
|
* Make sure the old inode table is reserved in the
|
|
|
|
* block reservation bitmap.
|
1997-06-09 18:51:29 +04:00
|
|
|
*/
|
1997-06-12 11:14:32 +04:00
|
|
|
for (blk = rfs->old_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);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-09 18:51:29 +04:00
|
|
|
next_group:
|
|
|
|
group_blk += rfs->new_fs->super->s_blocks_per_group;
|
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
retval = 0;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
if (meta_bmap)
|
|
|
|
ext2fs_free_block_bitmap(meta_bmap);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-17 07:52:12 +04:00
|
|
|
return retval;
|
1997-06-09 18:51:29 +04:00
|
|
|
}
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* This helper function tries to allocate a new block. We try to
|
|
|
|
* avoid hitting the original group descriptor blocks at least at
|
|
|
|
* first, since we want to make it possible to recover from a badly
|
|
|
|
* aborted resize operation as much as possible.
|
|
|
|
*
|
|
|
|
* In the future, I may further modify this routine to balance out
|
|
|
|
* where we get the new blocks across the various block groups.
|
|
|
|
* Ideally we would allocate blocks that corresponded with the block
|
|
|
|
* group of the containing inode, and keep contiguous blocks
|
|
|
|
* together. However, this very difficult to do efficiently, since we
|
|
|
|
* don't have the necessary information up front.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define AVOID_OLD 1
|
|
|
|
#define DESPERATION 2
|
|
|
|
|
|
|
|
static void init_block_alloc(ext2_resize_t rfs)
|
|
|
|
{
|
|
|
|
rfs->alloc_state = AVOID_OLD;
|
|
|
|
rfs->new_blk = rfs->new_fs->super->s_first_data_block;
|
1998-03-21 06:27:48 +03:00
|
|
|
#if 0
|
|
|
|
/* HACK for testing */
|
|
|
|
if (rfs->new_fs->super->s_blocks_count >
|
|
|
|
rfs->old_fs->super->s_blocks_count)
|
|
|
|
rfs->new_blk = rfs->old_fs->super->s_blocks_count;
|
|
|
|
#endif
|
1998-02-17 01:16:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static blk_t get_new_block(ext2_resize_t rfs)
|
|
|
|
{
|
|
|
|
ext2_filsys fs = rfs->new_fs;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
while (1) {
|
|
|
|
if (rfs->new_blk >= fs->super->s_blocks_count) {
|
|
|
|
if (rfs->alloc_state == DESPERATION)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (rfs->flags & RESIZE_DEBUG_BMOVE)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Going into desperation mode "
|
|
|
|
"for block allocations\n");
|
2008-08-28 07:07:54 +04:00
|
|
|
#endif
|
1998-02-17 01:16:20 +03:00
|
|
|
rfs->alloc_state = DESPERATION;
|
|
|
|
rfs->new_blk = fs->super->s_first_data_block;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (ext2fs_test_block_bitmap(fs->block_map, rfs->new_blk) ||
|
|
|
|
ext2fs_test_block_bitmap(rfs->reserve_blocks,
|
|
|
|
rfs->new_blk) ||
|
|
|
|
((rfs->alloc_state == AVOID_OLD) &&
|
1998-03-08 02:24:01 +03:00
|
|
|
(rfs->new_blk < rfs->old_fs->super->s_blocks_count) &&
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_test_block_bitmap(rfs->old_fs->block_map,
|
|
|
|
rfs->new_blk))) {
|
|
|
|
rfs->new_blk++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
return rfs->new_blk;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-22 11:07:53 +04:00
|
|
|
static errcode_t resize2fs_get_alloc_block(ext2_filsys fs, blk64_t goal,
|
|
|
|
blk64_t *ret)
|
|
|
|
{
|
|
|
|
ext2_resize_t rfs = (ext2_resize_t) fs->priv_data;
|
|
|
|
blk_t blk;
|
|
|
|
|
|
|
|
blk = get_new_block(rfs);
|
|
|
|
if (!blk)
|
|
|
|
return ENOSPC;
|
|
|
|
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (rfs->flags & 0xF)
|
|
|
|
printf("get_alloc_block allocating %u\n", blk);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ext2fs_mark_block_bitmap(rfs->old_fs->block_map, blk);
|
|
|
|
ext2fs_mark_block_bitmap(rfs->new_fs->block_map, blk);
|
|
|
|
*ret = (blk64_t) blk;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
static errcode_t block_mover(ext2_resize_t rfs)
|
|
|
|
{
|
|
|
|
blk_t blk, old_blk, new_blk;
|
|
|
|
ext2_filsys fs = rfs->new_fs;
|
|
|
|
ext2_filsys old_fs = rfs->old_fs;
|
|
|
|
errcode_t retval;
|
|
|
|
int size, c;
|
|
|
|
int to_move, moved;
|
2003-06-25 01:34:02 +04:00
|
|
|
ext2_badblocks_list badblock_list = 0;
|
|
|
|
int bb_modified = 0;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2008-08-22 11:07:53 +04:00
|
|
|
fs->get_alloc_block = resize2fs_get_alloc_block;
|
|
|
|
old_fs->get_alloc_block = resize2fs_get_alloc_block;
|
|
|
|
|
2003-06-25 01:34:02 +04:00
|
|
|
retval = ext2fs_read_bb_inode(old_fs, &badblock_list);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
1998-02-17 01:16:20 +03:00
|
|
|
|
|
|
|
new_blk = fs->super->s_first_data_block;
|
|
|
|
if (!rfs->itable_buf) {
|
2007-12-27 18:08:13 +03:00
|
|
|
retval = ext2fs_get_array(fs->blocksize,
|
1998-02-17 01:16:20 +03:00
|
|
|
fs->inode_blocks_per_group,
|
2003-08-01 17:41:07 +04:00
|
|
|
&rfs->itable_buf);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
retval = ext2fs_create_extent_table(&rfs->bmap, 0);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The first step is to figure out where all of the blocks
|
|
|
|
* will go.
|
|
|
|
*/
|
|
|
|
to_move = moved = 0;
|
|
|
|
init_block_alloc(rfs);
|
|
|
|
for (blk = old_fs->super->s_first_data_block;
|
|
|
|
blk < old_fs->super->s_blocks_count; blk++) {
|
|
|
|
if (!ext2fs_test_block_bitmap(old_fs->block_map, blk))
|
|
|
|
continue;
|
|
|
|
if (!ext2fs_test_block_bitmap(rfs->move_blocks, blk))
|
|
|
|
continue;
|
2003-06-25 01:34:02 +04:00
|
|
|
if (ext2fs_badblocks_list_test(badblock_list, blk)) {
|
|
|
|
ext2fs_badblocks_list_del(badblock_list, blk);
|
|
|
|
bb_modified++;
|
|
|
|
continue;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
|
|
|
|
new_blk = get_new_block(rfs);
|
|
|
|
if (!new_blk) {
|
|
|
|
retval = ENOSPC;
|
|
|
|
goto errout;
|
|
|
|
}
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, new_blk, +1);
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_add_extent_entry(rfs->bmap, blk, new_blk);
|
|
|
|
to_move++;
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
if (to_move == 0) {
|
2002-07-26 09:56:22 +04:00
|
|
|
if (rfs->bmap) {
|
|
|
|
ext2fs_free_extent_table(rfs->bmap);
|
|
|
|
rfs->bmap = 0;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = 0;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Step two is to actually move the blocks
|
|
|
|
*/
|
|
|
|
retval = ext2fs_iterate_extent(rfs->bmap, 0, 0, 0);
|
|
|
|
if (retval) goto errout;
|
|
|
|
|
1998-02-24 23:24:49 +03:00
|
|
|
if (rfs->progress) {
|
|
|
|
retval = (rfs->progress)(rfs, E2_RSZ_BLOCK_RELOC_PASS,
|
|
|
|
0, to_move);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
while (1) {
|
|
|
|
retval = ext2fs_iterate_extent(rfs->bmap, &old_blk, &new_blk, &size);
|
|
|
|
if (retval) goto errout;
|
|
|
|
if (!size)
|
|
|
|
break;
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (rfs->flags & RESIZE_DEBUG_BMOVE)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Moving %d blocks %u->%u\n",
|
|
|
|
size, old_blk, new_blk);
|
1998-02-17 01:16:20 +03:00
|
|
|
#endif
|
|
|
|
do {
|
|
|
|
c = size;
|
|
|
|
if (c > fs->inode_blocks_per_group)
|
|
|
|
c = fs->inode_blocks_per_group;
|
|
|
|
retval = io_channel_read_blk(fs->io, old_blk, c,
|
|
|
|
rfs->itable_buf);
|
|
|
|
if (retval) goto errout;
|
|
|
|
retval = io_channel_write_blk(fs->io, new_blk, c,
|
|
|
|
rfs->itable_buf);
|
|
|
|
if (retval) goto errout;
|
|
|
|
size -= c;
|
|
|
|
new_blk += c;
|
|
|
|
old_blk += c;
|
|
|
|
moved += c;
|
|
|
|
if (rfs->progress) {
|
|
|
|
io_channel_flush(fs->io);
|
1998-02-24 23:24:49 +03:00
|
|
|
retval = (rfs->progress)(rfs,
|
|
|
|
E2_RSZ_BLOCK_RELOC_PASS,
|
1998-02-17 01:16:20 +03:00
|
|
|
moved, to_move);
|
1998-02-24 23:24:49 +03:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
1998-02-17 01:16:20 +03:00
|
|
|
}
|
|
|
|
} while (size > 0);
|
|
|
|
io_channel_flush(fs->io);
|
|
|
|
}
|
|
|
|
|
|
|
|
errout:
|
2003-06-25 01:34:02 +04:00
|
|
|
if (badblock_list) {
|
|
|
|
if (!retval && bb_modified)
|
|
|
|
retval = ext2fs_update_bb_inode(old_fs,
|
|
|
|
badblock_list);
|
|
|
|
ext2fs_badblocks_list_free(badblock_list);
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Resize processing, phase 3
|
|
|
|
*
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
struct process_block_struct {
|
|
|
|
ext2_resize_t rfs;
|
ChangeLog, libext2fs.texinfo:
libext2fs.texinfo: Change ino_t to ext2_ino_t
ChangeLog, extent.c, main.c, resize2fs.c:
extent.c, main.c, resize2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, mke2fs.c:
mke2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, test_icount.c, test_rel.c:
test_icount.c, test_rel.c: Change ino_t to ext2_ino_t
2001-01-11 18:38:00 +03:00
|
|
|
ext2_ino_t ino;
|
1998-02-17 01:16:20 +03:00
|
|
|
struct ext2_inode * inode;
|
|
|
|
errcode_t error;
|
|
|
|
int is_dir;
|
|
|
|
int changed;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int process_block(ext2_filsys fs, blk_t *block_nr,
|
2008-08-28 07:07:54 +04:00
|
|
|
e2_blkcnt_t blockcnt,
|
2003-12-07 09:28:50 +03:00
|
|
|
blk_t ref_block EXT2FS_ATTR((unused)),
|
|
|
|
int ref_offset EXT2FS_ATTR((unused)), void *priv_data)
|
1998-02-17 01:16:20 +03:00
|
|
|
{
|
|
|
|
struct process_block_struct *pb;
|
|
|
|
errcode_t retval;
|
|
|
|
blk_t block, new_block;
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
pb = (struct process_block_struct *) priv_data;
|
|
|
|
block = *block_nr;
|
|
|
|
if (pb->rfs->bmap) {
|
|
|
|
new_block = ext2fs_extent_translate(pb->rfs->bmap, block);
|
|
|
|
if (new_block) {
|
|
|
|
*block_nr = new_block;
|
|
|
|
ret |= BLOCK_CHANGED;
|
|
|
|
pb->changed = 1;
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (pb->rfs->flags & RESIZE_DEBUG_BMOVE)
|
2008-08-28 07:07:54 +04:00
|
|
|
printf("ino=%u, blockcnt=%lld, %u->%u\n",
|
1998-02-17 01:16:20 +03:00
|
|
|
pb->ino, blockcnt, block, new_block);
|
|
|
|
#endif
|
|
|
|
block = new_block;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (pb->is_dir) {
|
|
|
|
retval = ext2fs_add_dir_block(fs->dblist, pb->ino,
|
1998-03-24 19:27:11 +03:00
|
|
|
block, (int) blockcnt);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval) {
|
|
|
|
pb->error = retval;
|
|
|
|
ret |= BLOCK_ABORT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Progress callback
|
|
|
|
*/
|
2008-08-28 07:07:54 +04:00
|
|
|
static errcode_t progress_callback(ext2_filsys fs,
|
2003-12-07 09:28:50 +03:00
|
|
|
ext2_inode_scan scan EXT2FS_ATTR((unused)),
|
1998-02-17 01:16:20 +03:00
|
|
|
dgrp_t group, void * priv_data)
|
|
|
|
{
|
|
|
|
ext2_resize_t rfs = (ext2_resize_t) priv_data;
|
1998-02-24 23:24:49 +03:00
|
|
|
errcode_t retval;
|
1998-02-17 01:16:20 +03:00
|
|
|
|
|
|
|
/*
|
1998-02-21 07:20:44 +03:00
|
|
|
* This check is to protect against old ext2 libraries. It
|
|
|
|
* shouldn't be needed against new libraries.
|
1998-02-17 01:16:20 +03:00
|
|
|
*/
|
1998-02-21 07:20:44 +03:00
|
|
|
if ((group+1) == 0)
|
1998-02-17 01:16:20 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (rfs->progress) {
|
|
|
|
io_channel_flush(fs->io);
|
1998-02-24 23:24:49 +03:00
|
|
|
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
|
|
|
group+1, fs->group_desc_count);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
1998-02-17 01:16:20 +03:00
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static errcode_t inode_scan_and_fix(ext2_resize_t rfs)
|
|
|
|
{
|
|
|
|
struct process_block_struct pb;
|
ChangeLog, libext2fs.texinfo:
libext2fs.texinfo: Change ino_t to ext2_ino_t
ChangeLog, extent.c, main.c, resize2fs.c:
extent.c, main.c, resize2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, mke2fs.c:
mke2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, test_icount.c, test_rel.c:
test_icount.c, test_rel.c: Change ino_t to ext2_ino_t
2001-01-11 18:38:00 +03:00
|
|
|
ext2_ino_t ino, new_inode;
|
2008-03-09 04:20:40 +03:00
|
|
|
struct ext2_inode *inode = NULL;
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2_inode_scan scan = NULL;
|
|
|
|
errcode_t retval;
|
|
|
|
char *block_buf = 0;
|
ChangeLog, libext2fs.texinfo:
libext2fs.texinfo: Change ino_t to ext2_ino_t
ChangeLog, extent.c, main.c, resize2fs.c:
extent.c, main.c, resize2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, mke2fs.c:
mke2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, test_icount.c, test_rel.c:
test_icount.c, test_rel.c: Change ino_t to ext2_ino_t
2001-01-11 18:38:00 +03:00
|
|
|
ext2_ino_t start_to_move;
|
2002-08-17 01:07:06 +04:00
|
|
|
blk_t orig_size, new_block;
|
2008-02-28 22:24:17 +03:00
|
|
|
int inode_size;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
if ((rfs->old_fs->group_desc_count <=
|
|
|
|
rfs->new_fs->group_desc_count) &&
|
|
|
|
!rfs->bmap)
|
|
|
|
return 0;
|
|
|
|
|
1998-03-21 06:27:48 +03:00
|
|
|
/*
|
|
|
|
* Save the original size of the old filesystem, and
|
|
|
|
* temporarily set the size to be the new size if the new size
|
|
|
|
* is larger. We need to do this to avoid catching an error
|
|
|
|
* by the block iterator routines
|
|
|
|
*/
|
|
|
|
orig_size = rfs->old_fs->super->s_blocks_count;
|
|
|
|
if (orig_size < rfs->new_fs->super->s_blocks_count)
|
|
|
|
rfs->old_fs->super->s_blocks_count =
|
|
|
|
rfs->new_fs->super->s_blocks_count;
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = ext2fs_open_inode_scan(rfs->old_fs, 0, &scan);
|
|
|
|
if (retval) goto errout;
|
|
|
|
|
|
|
|
retval = ext2fs_init_dblist(rfs->old_fs, 0);
|
|
|
|
if (retval) goto errout;
|
2007-12-27 18:08:13 +03:00
|
|
|
retval = ext2fs_get_array(rfs->old_fs->blocksize, 3, &block_buf);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval) goto errout;
|
|
|
|
|
|
|
|
start_to_move = (rfs->new_fs->group_desc_count *
|
|
|
|
rfs->new_fs->super->s_inodes_per_group);
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-24 23:24:49 +03:00
|
|
|
if (rfs->progress) {
|
|
|
|
retval = (rfs->progress)(rfs, E2_RSZ_INODE_SCAN_PASS,
|
|
|
|
0, rfs->old_fs->group_desc_count);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_set_inode_callback(scan, progress_callback, (void *) rfs);
|
|
|
|
pb.rfs = rfs;
|
2008-03-09 04:20:40 +03:00
|
|
|
pb.inode = inode;
|
1998-02-17 01:16:20 +03:00
|
|
|
pb.error = 0;
|
|
|
|
new_inode = EXT2_FIRST_INODE(rfs->new_fs->super);
|
2008-02-28 22:24:17 +03:00
|
|
|
inode_size = EXT2_INODE_SIZE(rfs->new_fs->super);
|
2008-03-09 04:20:40 +03:00
|
|
|
inode = malloc(inode_size);
|
|
|
|
if (!inode) {
|
2008-02-28 22:24:17 +03:00
|
|
|
retval = ENOMEM;
|
|
|
|
goto errout;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* First, copy all of the inodes that need to be moved
|
|
|
|
* elsewhere in the inode table
|
|
|
|
*/
|
|
|
|
while (1) {
|
2008-03-09 04:20:40 +03:00
|
|
|
retval = ext2fs_get_next_inode_full(scan, &ino, inode, inode_size);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval) goto errout;
|
|
|
|
if (!ino)
|
|
|
|
break;
|
|
|
|
|
2008-03-09 04:20:40 +03:00
|
|
|
if (inode->i_links_count == 0 && ino != EXT2_RESIZE_INO)
|
1998-02-17 01:16:20 +03:00
|
|
|
continue; /* inode not in use */
|
|
|
|
|
2008-03-09 04:20:40 +03:00
|
|
|
pb.is_dir = LINUX_S_ISDIR(inode->i_mode);
|
1998-02-17 01:16:20 +03:00
|
|
|
pb.changed = 0;
|
|
|
|
|
2008-03-09 04:20:40 +03:00
|
|
|
if (inode->i_file_acl && rfs->bmap) {
|
2008-08-28 07:07:54 +04:00
|
|
|
new_block = ext2fs_extent_translate(rfs->bmap,
|
2008-03-09 04:20:40 +03:00
|
|
|
inode->i_file_acl);
|
2002-08-17 01:03:59 +04:00
|
|
|
if (new_block) {
|
2008-03-09 04:20:40 +03:00
|
|
|
inode->i_file_acl = new_block;
|
2008-08-28 07:07:54 +04:00
|
|
|
retval = ext2fs_write_inode_full(rfs->old_fs,
|
2008-03-09 04:20:40 +03:00
|
|
|
ino, inode, inode_size);
|
2002-08-17 01:03:59 +04:00
|
|
|
if (retval) goto errout;
|
|
|
|
}
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2008-03-09 04:20:40 +03:00
|
|
|
if (ext2fs_inode_has_valid_blocks(inode) &&
|
1998-02-17 01:16:20 +03:00
|
|
|
(rfs->bmap || pb.is_dir)) {
|
|
|
|
pb.ino = ino;
|
|
|
|
retval = ext2fs_block_iterate2(rfs->old_fs,
|
|
|
|
ino, 0, block_buf,
|
|
|
|
process_block, &pb);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
if (pb.error) {
|
|
|
|
retval = pb.error;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ino <= start_to_move)
|
|
|
|
continue; /* Don't need to move it. */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Find a new inode
|
|
|
|
*/
|
2008-08-22 11:03:42 +04:00
|
|
|
retval = ext2fs_new_inode(rfs->new_fs, 0, 0, 0, &new_inode);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_inode_alloc_stats2(rfs->new_fs, new_inode, +1,
|
|
|
|
pb.is_dir);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (pb.changed) {
|
|
|
|
/* Get the new version of the inode */
|
2008-02-28 22:24:17 +03:00
|
|
|
retval = ext2fs_read_inode_full(rfs->old_fs, ino,
|
2008-03-09 04:20:40 +03:00
|
|
|
inode, inode_size);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval) goto errout;
|
|
|
|
}
|
2008-03-09 04:20:40 +03:00
|
|
|
inode->i_ctime = time(0);
|
2008-02-28 22:24:17 +03:00
|
|
|
retval = ext2fs_write_inode_full(rfs->old_fs, new_inode,
|
2008-03-09 04:20:40 +03:00
|
|
|
inode, inode_size);
|
1998-02-17 01:16:20 +03:00
|
|
|
if (retval) goto errout;
|
|
|
|
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (rfs->flags & RESIZE_DEBUG_INODEMAP)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Inode moved %u->%u\n", ino, new_inode);
|
1998-02-17 01:16:20 +03:00
|
|
|
#endif
|
|
|
|
if (!rfs->imap) {
|
|
|
|
retval = ext2fs_create_extent_table(&rfs->imap, 0);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
ext2fs_add_extent_entry(rfs->imap, ino, new_inode);
|
|
|
|
}
|
|
|
|
io_channel_flush(rfs->old_fs->io);
|
|
|
|
|
|
|
|
errout:
|
1998-03-21 06:27:48 +03:00
|
|
|
rfs->old_fs->super->s_blocks_count = orig_size;
|
1998-02-17 01:16:20 +03:00
|
|
|
if (rfs->bmap) {
|
|
|
|
ext2fs_free_extent_table(rfs->bmap);
|
|
|
|
rfs->bmap = 0;
|
|
|
|
}
|
|
|
|
if (scan)
|
|
|
|
ext2fs_close_inode_scan(scan);
|
|
|
|
if (block_buf)
|
2003-08-01 17:41:07 +04:00
|
|
|
ext2fs_free_mem(&block_buf);
|
2008-03-09 04:20:40 +03:00
|
|
|
if (inode)
|
|
|
|
free(inode);
|
1998-02-17 01:16:20 +03:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Resize processing, phase 4.
|
|
|
|
*
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct istruct {
|
|
|
|
ext2_resize_t rfs;
|
1998-02-24 23:24:49 +03:00
|
|
|
errcode_t err;
|
2008-11-16 18:03:00 +03:00
|
|
|
unsigned int max_dirs;
|
|
|
|
unsigned int num;
|
1998-02-17 01:16:20 +03:00
|
|
|
};
|
|
|
|
|
2008-08-28 07:07:54 +04:00
|
|
|
static int check_and_change_inodes(ext2_ino_t dir,
|
2003-12-07 09:28:50 +03:00
|
|
|
int entry EXT2FS_ATTR((unused)),
|
1998-02-17 01:16:20 +03:00
|
|
|
struct ext2_dir_entry *dirent, int offset,
|
2003-12-07 09:28:50 +03:00
|
|
|
int blocksize EXT2FS_ATTR((unused)),
|
2008-08-28 07:07:54 +04:00
|
|
|
char *buf EXT2FS_ATTR((unused)),
|
2003-12-07 09:28:50 +03:00
|
|
|
void *priv_data)
|
1998-02-17 01:16:20 +03:00
|
|
|
{
|
|
|
|
struct istruct *is = (struct istruct *) priv_data;
|
2002-11-01 03:56:56 +03:00
|
|
|
struct ext2_inode inode;
|
|
|
|
ext2_ino_t new_inode;
|
|
|
|
errcode_t retval;
|
1998-02-17 01:16:20 +03:00
|
|
|
|
|
|
|
if (is->rfs->progress && offset == 0) {
|
|
|
|
io_channel_flush(is->rfs->old_fs->io);
|
1998-02-24 23:24:49 +03:00
|
|
|
is->err = (is->rfs->progress)(is->rfs,
|
|
|
|
E2_RSZ_INODE_REF_UPD_PASS,
|
1998-09-03 04:26:49 +04:00
|
|
|
++is->num, is->max_dirs);
|
1998-02-24 23:24:49 +03:00
|
|
|
if (is->err)
|
|
|
|
return DIRENT_ABORT;
|
1998-02-17 01:16:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!dirent->inode)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
new_inode = ext2fs_extent_translate(is->rfs->imap, dirent->inode);
|
|
|
|
|
|
|
|
if (!new_inode)
|
|
|
|
return 0;
|
|
|
|
#ifdef RESIZE2FS_DEBUG
|
|
|
|
if (is->rfs->flags & RESIZE_DEBUG_INODEMAP)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Inode translate (dir=%u, name=%.*s, %u->%u)\n",
|
2004-09-18 01:10:17 +04:00
|
|
|
dir, dirent->name_len&0xFF, dirent->name,
|
1998-02-17 01:16:20 +03:00
|
|
|
dirent->inode, new_inode);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
dirent->inode = new_inode;
|
|
|
|
|
2002-11-01 03:56:56 +03:00
|
|
|
/* Update the directory mtime and ctime */
|
|
|
|
retval = ext2fs_read_inode(is->rfs->old_fs, dir, &inode);
|
|
|
|
if (retval == 0) {
|
|
|
|
inode.i_mtime = inode.i_ctime = time(0);
|
2007-03-18 18:16:33 +03:00
|
|
|
is->err = ext2fs_write_inode(is->rfs->old_fs, dir, &inode);
|
|
|
|
if (is->err)
|
|
|
|
return DIRENT_ABORT;
|
2002-11-01 03:56:56 +03:00
|
|
|
}
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
return DIRENT_CHANGED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static errcode_t inode_ref_fix(ext2_resize_t rfs)
|
|
|
|
{
|
|
|
|
errcode_t retval;
|
|
|
|
struct istruct is;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
if (!rfs->imap)
|
|
|
|
return 0;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
/*
|
|
|
|
* Now, we iterate over all of the directories to update the
|
|
|
|
* inode references
|
|
|
|
*/
|
|
|
|
is.num = 0;
|
1998-09-03 04:26:49 +04:00
|
|
|
is.max_dirs = ext2fs_dblist_count(rfs->old_fs->dblist);
|
1998-02-17 01:16:20 +03:00
|
|
|
is.rfs = rfs;
|
1998-02-24 23:24:49 +03:00
|
|
|
is.err = 0;
|
1998-02-17 01:16:20 +03:00
|
|
|
|
1998-02-24 23:24:49 +03:00
|
|
|
if (rfs->progress) {
|
|
|
|
retval = (rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
|
1998-09-03 04:26:49 +04:00
|
|
|
0, is.max_dirs);
|
1998-02-24 23:24:49 +03:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
retval = ext2fs_dblist_dir_iterate(rfs->old_fs->dblist,
|
|
|
|
DIRENT_FLAG_INCLUDE_EMPTY, 0,
|
|
|
|
check_and_change_inodes, &is);
|
1998-02-24 23:24:49 +03:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
if (is.err) {
|
|
|
|
retval = is.err;
|
|
|
|
goto errout;
|
|
|
|
}
|
1998-02-17 01:16:20 +03:00
|
|
|
|
2008-08-22 17:26:26 +04:00
|
|
|
if (rfs->progress && (is.num < is.max_dirs))
|
|
|
|
(rfs->progress)(rfs, E2_RSZ_INODE_REF_UPD_PASS,
|
|
|
|
is.max_dirs, is.max_dirs);
|
|
|
|
|
1998-02-24 23:24:49 +03:00
|
|
|
errout:
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_free_extent_table(rfs->imap);
|
|
|
|
rfs->imap = 0;
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --------------------------------------------------------------------
|
|
|
|
*
|
|
|
|
* Resize processing, phase 5.
|
|
|
|
*
|
|
|
|
* In this phase we actually move the inode table around, and then
|
|
|
|
* update the summary statistics. This is scary, since aborting here
|
|
|
|
* will potentially scramble the filesystem. (We are moving the
|
|
|
|
* inode tables around in place, and so the potential for lost data,
|
|
|
|
* or at the very least scrambling the mapping between filenames and
|
|
|
|
* inode numbers is very high in case of a power failure here.)
|
|
|
|
* --------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1997-06-08 00:42:58 +04:00
|
|
|
|
1997-06-12 11:14:32 +04:00
|
|
|
/*
|
|
|
|
* A very scary routine --- this one moves the inode table around!!!
|
|
|
|
*
|
|
|
|
* After this you have to use the rfs->new_fs file handle to read and
|
|
|
|
* write inodes.
|
|
|
|
*/
|
1997-06-17 07:52:12 +04:00
|
|
|
static errcode_t move_itables(ext2_resize_t rfs)
|
1997-06-12 11:14:32 +04:00
|
|
|
{
|
2003-12-07 09:28:50 +03:00
|
|
|
int n, num, size, diff;
|
|
|
|
dgrp_t i, max_groups;
|
1997-06-12 11:14:32 +04:00
|
|
|
ext2_filsys fs = rfs->new_fs;
|
1997-06-14 11:28:44 +04:00
|
|
|
char *cp;
|
2005-01-26 18:03:56 +03:00
|
|
|
blk_t old_blk, new_blk, blk;
|
1998-02-17 01:16:20 +03:00
|
|
|
errcode_t retval;
|
2005-01-26 18:03:56 +03:00
|
|
|
int j, to_move, moved;
|
1997-06-12 11:14:32 +04:00
|
|
|
|
1998-09-03 04:26:49 +04:00
|
|
|
max_groups = fs->group_desc_count;
|
|
|
|
if (max_groups > rfs->old_fs->group_desc_count)
|
|
|
|
max_groups = rfs->old_fs->group_desc_count;
|
1997-06-12 11:14:32 +04:00
|
|
|
|
1997-06-14 11:28:44 +04:00
|
|
|
size = fs->blocksize * fs->inode_blocks_per_group;
|
|
|
|
if (!rfs->itable_buf) {
|
2003-08-01 17:41:07 +04:00
|
|
|
retval = ext2fs_get_mem(size, &rfs->itable_buf);
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
if (retval)
|
|
|
|
return retval;
|
1997-06-14 11:28:44 +04:00
|
|
|
}
|
1997-06-17 07:52:12 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out how many inode tables we need to move
|
|
|
|
*/
|
|
|
|
to_move = moved = 0;
|
1998-09-03 04:26:49 +04:00
|
|
|
for (i=0; i < max_groups; i++)
|
1997-06-17 07:52:12 +04:00
|
|
|
if (rfs->old_fs->group_desc[i].bg_inode_table !=
|
|
|
|
fs->group_desc[i].bg_inode_table)
|
|
|
|
to_move++;
|
|
|
|
|
|
|
|
if (to_move == 0)
|
|
|
|
return 0;
|
|
|
|
|
1998-02-24 23:24:49 +03:00
|
|
|
if (rfs->progress) {
|
|
|
|
retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
|
|
|
|
0, to_move);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
1998-02-14 01:58:18 +03:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
rfs->old_fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
|
|
|
|
|
1998-09-03 04:26:49 +04:00
|
|
|
for (i=0; i < max_groups; i++) {
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
old_blk = rfs->old_fs->group_desc[i].bg_inode_table;
|
|
|
|
new_blk = fs->group_desc[i].bg_inode_table;
|
|
|
|
diff = new_blk - old_blk;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-11-03 22:46:49 +03:00
|
|
|
#ifdef RESIZE2FS_DEBUG
|
2008-08-28 07:07:54 +04:00
|
|
|
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Itable move group %d block %u->%u (diff %d)\n",
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
i, old_blk, new_blk, diff);
|
1997-11-03 22:46:49 +03:00
|
|
|
#endif
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-14 11:28:44 +04:00
|
|
|
if (!diff)
|
1997-06-12 11:14:32 +04:00
|
|
|
continue;
|
|
|
|
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
retval = io_channel_read_blk(fs->io, old_blk,
|
1997-06-14 11:28:44 +04:00
|
|
|
fs->inode_blocks_per_group,
|
|
|
|
rfs->itable_buf);
|
2008-08-28 07:07:54 +04:00
|
|
|
if (retval)
|
1998-02-17 01:16:20 +03:00
|
|
|
goto errout;
|
1997-06-14 11:28:44 +04:00
|
|
|
/*
|
|
|
|
* The end of the inode table segment often contains
|
1998-02-17 01:16:20 +03:00
|
|
|
* all zeros, and we're often only moving the inode
|
|
|
|
* table down a block or two. If so, we can optimize
|
|
|
|
* things by not rewriting blocks that we know to be zero
|
|
|
|
* already.
|
1997-06-14 11:28:44 +04:00
|
|
|
*/
|
2005-08-09 03:57:04 +04:00
|
|
|
for (cp = rfs->itable_buf+size-1, n=0; n < size; n++, cp--)
|
1997-06-14 11:28:44 +04:00
|
|
|
if (*cp)
|
|
|
|
break;
|
|
|
|
n = n >> EXT2_BLOCK_SIZE_BITS(fs->super);
|
1997-11-03 22:46:49 +03:00
|
|
|
#ifdef RESIZE2FS_DEBUG
|
2008-08-28 07:07:54 +04:00
|
|
|
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("%d blocks of zeros...\n", n);
|
1997-11-03 22:46:49 +03:00
|
|
|
#endif
|
1997-06-14 11:28:44 +04:00
|
|
|
num = fs->inode_blocks_per_group;
|
|
|
|
if (n > diff)
|
|
|
|
num -= n;
|
|
|
|
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
retval = io_channel_write_blk(fs->io, new_blk,
|
1997-06-14 11:28:44 +04:00
|
|
|
num, rfs->itable_buf);
|
1997-06-12 11:14:32 +04:00
|
|
|
if (retval) {
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
io_channel_write_blk(fs->io, old_blk,
|
1997-06-14 11:28:44 +04:00
|
|
|
num, rfs->itable_buf);
|
1998-02-17 01:16:20 +03:00
|
|
|
goto errout;
|
1997-06-12 11:14:32 +04:00
|
|
|
}
|
1997-06-14 11:28:44 +04:00
|
|
|
if (n > diff) {
|
|
|
|
retval = io_channel_write_blk(fs->io,
|
Many files:
resize2fs.h: If EXT2_FLAT_INCLUDES is defined, then assume all
of the ext2-specific header files are in a flat directory.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
resize2fs.h: Rename variables named "new" to "new_block",
"new_inode", or "new_loc" to avoid C++ reserved word
clash.
ext2_block_move.c, ext2_inode_move.c, extent.c, resize2fs.c,
sim_progress.c: Use ext2fs_get_memory(),
ext2fs_free_memory(), et. al., instead of malloc() and
free().
ext2_block_move.c, ext2_inode_move.c, extent.c: Explicitly cast
all assignments from void * to be compatible with C++.
banalysis.c, banalysis.h, ext2_inode_move.c, ext2_block_move.c:
Change private to priv_data to avoid C++ namespace clash.
ChangeLog, badblocks.8.in:
badblocks.8.in: Add documentation for the -s option.
1998-01-19 17:55:24 +03:00
|
|
|
old_blk + fs->inode_blocks_per_group,
|
1998-02-17 01:16:20 +03:00
|
|
|
diff, (rfs->itable_buf +
|
|
|
|
(fs->inode_blocks_per_group - diff) *
|
|
|
|
fs->blocksize));
|
1997-06-14 11:28:44 +04:00
|
|
|
if (retval)
|
1998-02-17 01:16:20 +03:00
|
|
|
goto errout;
|
1997-06-17 07:52:12 +04:00
|
|
|
}
|
2005-01-26 18:03:56 +03:00
|
|
|
|
|
|
|
for (blk = rfs->old_fs->group_desc[i].bg_inode_table, j=0;
|
|
|
|
j < fs->inode_blocks_per_group ; j++, blk++)
|
2008-06-17 06:13:55 +04:00
|
|
|
ext2fs_block_alloc_stats(fs, blk, -1);
|
2005-01-26 18:03:56 +03:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
rfs->old_fs->group_desc[i].bg_inode_table = new_blk;
|
2007-10-22 06:03:52 +04:00
|
|
|
ext2fs_group_desc_csum_set(rfs->old_fs, i);
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_mark_super_dirty(rfs->old_fs);
|
2005-01-26 18:03:56 +03:00
|
|
|
ext2fs_flush(rfs->old_fs);
|
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
if (rfs->progress) {
|
1998-02-24 23:24:49 +03:00
|
|
|
retval = rfs->progress(rfs, E2_RSZ_MOVE_ITABLE_PASS,
|
|
|
|
++moved, to_move);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
1998-02-17 01:16:20 +03:00
|
|
|
}
|
1997-06-12 11:14:32 +04:00
|
|
|
}
|
2005-01-26 18:03:56 +03:00
|
|
|
mark_table_blocks(fs, fs->block_map);
|
1998-02-17 01:16:20 +03:00
|
|
|
ext2fs_flush(fs);
|
1997-11-03 22:46:49 +03:00
|
|
|
#ifdef RESIZE2FS_DEBUG
|
2008-08-28 07:07:54 +04:00
|
|
|
if (rfs->flags & RESIZE_DEBUG_ITABLEMOVE)
|
2005-05-10 00:22:17 +04:00
|
|
|
printf("Inode table move finished.\n");
|
1997-11-03 22:46:49 +03:00
|
|
|
#endif
|
1997-06-12 11:14:32 +04:00
|
|
|
return 0;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1998-02-17 01:16:20 +03:00
|
|
|
errout:
|
1997-06-12 11:14:32 +04:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2004-12-24 09:34:29 +03:00
|
|
|
/*
|
2008-08-28 07:07:54 +04:00
|
|
|
* Fix the resize inode
|
2004-12-24 09:34:29 +03:00
|
|
|
*/
|
|
|
|
static errcode_t fix_resize_inode(ext2_filsys fs)
|
|
|
|
{
|
|
|
|
struct ext2_inode inode;
|
|
|
|
errcode_t retval;
|
|
|
|
char * block_buf;
|
2008-07-10 22:18:41 +04:00
|
|
|
blk_t blk;
|
2004-12-24 09:34:29 +03:00
|
|
|
|
2008-08-28 07:07:54 +04:00
|
|
|
if (!(fs->super->s_feature_compat &
|
2004-12-24 09:34:29 +03:00
|
|
|
EXT2_FEATURE_COMPAT_RESIZE_INODE))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
retval = ext2fs_get_mem(fs->blocksize, &block_buf);
|
|
|
|
if (retval) goto errout;
|
|
|
|
|
|
|
|
retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode);
|
|
|
|
if (retval) goto errout;
|
|
|
|
|
2008-07-10 22:18:41 +04:00
|
|
|
if (fs->super->s_reserved_gdt_blocks == 0) {
|
2008-08-28 07:07:54 +04:00
|
|
|
fs->super->s_feature_compat &=
|
2008-07-10 22:18:41 +04:00
|
|
|
~EXT2_FEATURE_COMPAT_RESIZE_INODE;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
|
|
|
|
|
|
|
if ((blk = inode.i_block[EXT2_DIND_BLOCK]) != 0)
|
|
|
|
ext2fs_block_alloc_stats(fs, blk, -1);
|
|
|
|
|
|
|
|
memset(&inode, 0, sizeof(inode));
|
|
|
|
|
|
|
|
retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2008-04-09 19:39:11 +04:00
|
|
|
ext2fs_iblk_set(fs, &inode, 1);
|
2004-12-24 09:34:29 +03:00
|
|
|
|
|
|
|
retval = ext2fs_write_inode(fs, EXT2_RESIZE_INO, &inode);
|
|
|
|
if (retval) goto errout;
|
|
|
|
|
|
|
|
if (!inode.i_block[EXT2_DIND_BLOCK]) {
|
2008-08-28 07:07:54 +04:00
|
|
|
/*
|
2004-12-24 09:34:29 +03:00
|
|
|
* Avoid zeroing out block #0; that's rude. This
|
|
|
|
* should never happen anyway since the filesystem
|
|
|
|
* should be fsck'ed and we assume it is consistent.
|
|
|
|
*/
|
2008-08-28 07:07:54 +04:00
|
|
|
fprintf(stderr,
|
2005-05-10 00:22:17 +04:00
|
|
|
_("Should never happen: resize inode corrupt!\n"));
|
2004-12-24 09:34:29 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(block_buf, 0, fs->blocksize);
|
|
|
|
|
|
|
|
retval = io_channel_write_blk(fs->io, inode.i_block[EXT2_DIND_BLOCK],
|
|
|
|
1, block_buf);
|
|
|
|
if (retval) goto errout;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
2004-12-24 09:34:29 +03:00
|
|
|
retval = ext2fs_create_resize_inode(fs);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
|
|
|
|
errout:
|
|
|
|
if (block_buf)
|
|
|
|
ext2fs_free_mem(&block_buf);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
1997-06-12 11:14:32 +04:00
|
|
|
/*
|
|
|
|
* Finally, recalculate the summary information
|
|
|
|
*/
|
|
|
|
static errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs)
|
|
|
|
{
|
ChangeLog, libext2fs.texinfo:
libext2fs.texinfo: Change ino_t to ext2_ino_t
ChangeLog, extent.c, main.c, resize2fs.c:
extent.c, main.c, resize2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, mke2fs.c:
mke2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, test_icount.c, test_rel.c:
test_icount.c, test_rel.c: Change ino_t to ext2_ino_t
2001-01-11 18:38:00 +03:00
|
|
|
blk_t blk;
|
|
|
|
ext2_ino_t ino;
|
2003-12-07 09:28:50 +03:00
|
|
|
unsigned int group = 0;
|
|
|
|
unsigned int count = 0;
|
ChangeLog, libext2fs.texinfo:
libext2fs.texinfo: Change ino_t to ext2_ino_t
ChangeLog, extent.c, main.c, resize2fs.c:
extent.c, main.c, resize2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, mke2fs.c:
mke2fs.c: Change ino_t to ext2_ino_t.
ChangeLog, test_icount.c, test_rel.c:
test_icount.c, test_rel.c: Change ino_t to ext2_ino_t
2001-01-11 18:38:00 +03:00
|
|
|
int total_free = 0;
|
|
|
|
int group_free = 0;
|
2008-06-17 06:13:55 +04:00
|
|
|
int uninit = 0;
|
|
|
|
blk_t super_blk, old_desc_blk, new_desc_blk;
|
|
|
|
int old_desc_blocks;
|
1997-06-12 11:14:32 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* First calculate the block statistics
|
|
|
|
*/
|
2008-06-17 06:13:55 +04:00
|
|
|
uninit = fs->group_desc[group].bg_flags & EXT2_BG_BLOCK_UNINIT;
|
|
|
|
ext2fs_super_and_bgd_loc(fs, group, &super_blk, &old_desc_blk,
|
|
|
|
&new_desc_blk, 0);
|
|
|
|
if (fs->super->s_feature_incompat & EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
old_desc_blocks = fs->super->s_first_meta_bg;
|
|
|
|
else
|
|
|
|
old_desc_blocks = fs->desc_blocks +
|
|
|
|
fs->super->s_reserved_gdt_blocks;
|
1997-06-12 11:14:32 +04:00
|
|
|
for (blk = fs->super->s_first_data_block;
|
|
|
|
blk < fs->super->s_blocks_count; blk++) {
|
2008-06-17 06:13:55 +04:00
|
|
|
if ((uninit &&
|
|
|
|
!((blk == super_blk) ||
|
|
|
|
((old_desc_blk && old_desc_blocks &&
|
|
|
|
(blk >= old_desc_blk) &&
|
|
|
|
(blk < old_desc_blk + old_desc_blocks))) ||
|
|
|
|
((new_desc_blk && (blk == new_desc_blk))) ||
|
|
|
|
(blk == fs->group_desc[group].bg_block_bitmap) ||
|
|
|
|
(blk == fs->group_desc[group].bg_inode_bitmap) ||
|
|
|
|
((blk >= fs->group_desc[group].bg_inode_table &&
|
|
|
|
(blk < fs->group_desc[group].bg_inode_table
|
|
|
|
+ fs->inode_blocks_per_group))))) ||
|
|
|
|
(!ext2fs_fast_test_block_bitmap(fs->block_map, blk))) {
|
1997-06-12 11:14:32 +04:00
|
|
|
group_free++;
|
|
|
|
total_free++;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
if ((count == fs->super->s_blocks_per_group) ||
|
|
|
|
(blk == fs->super->s_blocks_count-1)) {
|
2007-10-22 06:03:52 +04:00
|
|
|
fs->group_desc[group].bg_free_blocks_count =
|
1997-06-12 11:14:32 +04:00
|
|
|
group_free;
|
2007-10-22 06:03:52 +04:00
|
|
|
ext2fs_group_desc_csum_set(fs, group);
|
|
|
|
group++;
|
1997-06-12 11:14:32 +04:00
|
|
|
count = 0;
|
|
|
|
group_free = 0;
|
2008-06-17 06:13:55 +04:00
|
|
|
uninit = (fs->group_desc[group].bg_flags &
|
|
|
|
EXT2_BG_BLOCK_UNINIT);
|
|
|
|
ext2fs_super_and_bgd_loc(fs, group, &super_blk,
|
|
|
|
&old_desc_blk,
|
|
|
|
&new_desc_blk, 0);
|
|
|
|
if (fs->super->s_feature_incompat &
|
|
|
|
EXT2_FEATURE_INCOMPAT_META_BG)
|
|
|
|
old_desc_blocks = fs->super->s_first_meta_bg;
|
|
|
|
else
|
|
|
|
old_desc_blocks = fs->desc_blocks +
|
|
|
|
fs->super->s_reserved_gdt_blocks;
|
1997-06-12 11:14:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fs->super->s_free_blocks_count = total_free;
|
2008-08-28 07:07:54 +04:00
|
|
|
|
1997-06-12 11:14:32 +04:00
|
|
|
/*
|
|
|
|
* Next, calculate the inode statistics
|
|
|
|
*/
|
|
|
|
group_free = 0;
|
|
|
|
total_free = 0;
|
|
|
|
count = 0;
|
|
|
|
group = 0;
|
2006-08-30 10:16:55 +04:00
|
|
|
|
|
|
|
/* Protect loop from wrap-around if s_inodes_count maxed */
|
2008-06-17 06:13:55 +04:00
|
|
|
uninit = fs->group_desc[group].bg_flags & EXT2_BG_INODE_UNINIT;
|
2006-08-30 10:16:55 +04:00
|
|
|
for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
|
2008-06-17 06:13:55 +04:00
|
|
|
if (uninit ||
|
|
|
|
!ext2fs_fast_test_inode_bitmap(fs->inode_map, ino)) {
|
1997-06-12 11:14:32 +04:00
|
|
|
group_free++;
|
|
|
|
total_free++;
|
|
|
|
}
|
|
|
|
count++;
|
|
|
|
if ((count == fs->super->s_inodes_per_group) ||
|
|
|
|
(ino == fs->super->s_inodes_count)) {
|
2007-10-22 06:03:52 +04:00
|
|
|
fs->group_desc[group].bg_free_inodes_count =
|
1997-06-12 11:14:32 +04:00
|
|
|
group_free;
|
2007-10-22 06:03:52 +04:00
|
|
|
ext2fs_group_desc_csum_set(fs, group);
|
|
|
|
group++;
|
1997-06-12 11:14:32 +04:00
|
|
|
count = 0;
|
|
|
|
group_free = 0;
|
2008-06-17 06:13:55 +04:00
|
|
|
uninit = (fs->group_desc[group].bg_flags &
|
|
|
|
EXT2_BG_INODE_UNINIT);
|
1997-06-12 11:14:32 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fs->super->s_free_inodes_count = total_free;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-03-13 20:46:10 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* calcluate the minimum number of blocks the given fs can be resized to
|
|
|
|
*/
|
|
|
|
blk_t calculate_minimum_resize_size(ext2_filsys fs)
|
|
|
|
{
|
2008-06-07 19:52:33 +04:00
|
|
|
blk_t inode_count, blks_needed, groups, data_blocks;
|
2008-03-13 20:46:10 +03:00
|
|
|
blk_t grp, data_needed, last_start;
|
2008-06-07 19:52:33 +04:00
|
|
|
int overhead = 0, num_of_superblocks = 0;
|
2008-03-13 20:46:10 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* first figure out how many group descriptors we need to
|
|
|
|
* handle the number of inodes we have
|
|
|
|
*/
|
|
|
|
inode_count = fs->super->s_inodes_count -
|
|
|
|
fs->super->s_free_inodes_count;
|
|
|
|
blks_needed = ext2fs_div_ceil(inode_count,
|
|
|
|
fs->super->s_inodes_per_group) *
|
|
|
|
EXT2_BLOCKS_PER_GROUP(fs->super);
|
|
|
|
groups = ext2fs_div_ceil(blks_needed,
|
|
|
|
EXT2_BLOCKS_PER_GROUP(fs->super));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we need to figure out how many backup superblocks we have so we can
|
|
|
|
* account for that in the metadata
|
|
|
|
*/
|
|
|
|
for (grp = 0; grp < fs->group_desc_count; grp++) {
|
|
|
|
if (ext2fs_bg_has_super(fs, grp))
|
|
|
|
num_of_superblocks++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate how many blocks are needed for data */
|
|
|
|
data_needed = fs->super->s_blocks_count -
|
|
|
|
fs->super->s_free_blocks_count;
|
|
|
|
data_needed -= SUPER_OVERHEAD(fs) * num_of_superblocks;
|
|
|
|
data_needed -= META_OVERHEAD(fs) * fs->group_desc_count;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* figure out how many data blocks we have given the number of groups
|
|
|
|
* we need for our inodes
|
|
|
|
*/
|
|
|
|
data_blocks = groups * EXT2_BLOCKS_PER_GROUP(fs->super);
|
|
|
|
last_start = 0;
|
|
|
|
for (grp = 0; grp < groups; grp++) {
|
|
|
|
overhead = META_OVERHEAD(fs);
|
|
|
|
|
|
|
|
if (ext2fs_bg_has_super(fs, grp))
|
|
|
|
overhead += SUPER_OVERHEAD(fs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we want to keep track of how much data we can store in
|
|
|
|
* the groups leading up to the last group so we can determine
|
|
|
|
* how big the last group needs to be
|
|
|
|
*/
|
|
|
|
if (grp != (groups - 1))
|
|
|
|
last_start += EXT2_BLOCKS_PER_GROUP(fs->super) -
|
|
|
|
overhead;
|
|
|
|
|
|
|
|
data_blocks -= overhead;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if we need more group descriptors in order to accomodate our data
|
|
|
|
* then we need to add them here
|
|
|
|
*/
|
|
|
|
while (data_needed > data_blocks) {
|
|
|
|
blk_t remainder = data_needed - data_blocks;
|
|
|
|
blk_t extra_grps;
|
|
|
|
|
|
|
|
/* figure out how many more groups we need for the data */
|
|
|
|
extra_grps = ext2fs_div_ceil(remainder,
|
|
|
|
EXT2_BLOCKS_PER_GROUP(fs->super));
|
|
|
|
|
|
|
|
data_blocks += extra_grps * EXT2_BLOCKS_PER_GROUP(fs->super);
|
|
|
|
|
|
|
|
/* ok we have to account for the last group */
|
|
|
|
overhead = META_OVERHEAD(fs);
|
|
|
|
if (ext2fs_bg_has_super(fs, groups-1))
|
|
|
|
overhead += SUPER_OVERHEAD(fs);
|
|
|
|
last_start += EXT2_BLOCKS_PER_GROUP(fs->super) - overhead;
|
|
|
|
|
|
|
|
for (grp = groups; grp < groups+extra_grps; grp++) {
|
|
|
|
overhead = META_OVERHEAD(fs);
|
|
|
|
if (ext2fs_bg_has_super(fs, grp))
|
|
|
|
overhead += SUPER_OVERHEAD(fs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* again, we need to see how much data we cram into
|
|
|
|
* all of the groups leading up to the last group
|
|
|
|
*/
|
|
|
|
if (grp != (groups + extra_grps - 1))
|
|
|
|
last_start += EXT2_BLOCKS_PER_GROUP(fs->super)
|
|
|
|
- overhead;
|
|
|
|
|
|
|
|
data_blocks -= overhead;
|
|
|
|
}
|
|
|
|
|
|
|
|
groups += extra_grps;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now for the fun voodoo */
|
|
|
|
overhead = META_OVERHEAD(fs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* if this is the case then the last group is going to have data in it
|
|
|
|
* so we need to adjust the size of the last group accordingly
|
|
|
|
*/
|
|
|
|
if (last_start < data_needed) {
|
|
|
|
blk_t remainder = data_needed - last_start;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 50 is a magic number that mkfs/resize uses to see if its
|
|
|
|
* even worth making/resizing the fs. basically you need to
|
|
|
|
* have at least 50 blocks in addition to the blocks needed
|
|
|
|
* for the metadata in the last group
|
|
|
|
*/
|
|
|
|
if (remainder > 50)
|
|
|
|
overhead += remainder;
|
|
|
|
else
|
|
|
|
overhead += 50;
|
|
|
|
} else
|
|
|
|
overhead += 50;
|
|
|
|
|
|
|
|
if (ext2fs_bg_has_super(fs, groups-1))
|
|
|
|
overhead += SUPER_OVERHEAD(fs);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* since our last group doesn't have to be BLOCKS_PER_GROUP large, we
|
|
|
|
* only do groups-1, and then add the number of blocks needed to
|
|
|
|
* handle the group descriptor metadata+data that we need
|
|
|
|
*/
|
|
|
|
blks_needed = (groups-1) * EXT2_BLOCKS_PER_GROUP(fs->super);
|
|
|
|
blks_needed += overhead;
|
|
|
|
|
|
|
|
return blks_needed;
|
|
|
|
}
|