/*
* linux/fs/ext3/resize.c
*
* Support for resizing an ext3 filesystem while it is mounted.
*
* Copyright (C) 2001, 2002 Andreas Dilger <adilger@clusterfs.com>
*
* This could probably be made into a module, because it is not often in use.
*/
#define EXT3FS_DEBUG
#include <linux/smp_lock.h>
#include <linux/ext3_jbd.h>
#include <linux/errno.h>
#include <linux/slab.h>
#define outside(b, first, last) ((b) < (first) || (b) >= (last))
#define inside(b, first, last) ((b) >= (first) && (b) < (last))
static int verify_group_input(struct super_block *sb,
struct ext3_new_group_data *input)
{
struct ext3_sb_info *sbi = EXT3_SB(sb);
struct ext3_super_block *es = sbi->s_es;
ext3_fsblk_t start = le32_to_cpu(es->s_blocks_count);
ext3_fsblk_t end = start + input->blocks_count;
unsigned group = input->group;
ext3_fsblk_t itend = input->inode_table + sbi->s_itb_per_group;
unsigned overhead = ext3_bg_has_super(sb, group) ?
(1 + ext3_bg_num_gdb(sb, group) +
le16_to_cpu(es->s_reserved_gdt_blocks)) : 0;
ext3_fsblk_t metaend = start + overhead;
struct buffer_head *bh = NULL;
ext3_grpblk_t free_blocks_count;
int err = -EINVAL;
input->free_blocks_count = free_blocks_count =
input->blocks_count - 2 - overhead - sbi->s_itb_per_group;
if (test_opt(sb, DEBUG))
printk(KERN_DEBUG "EXT3-fs: adding %s group %u: %u blocks "
"(%d free, %u reserved)\n",
ext3_bg_has_super(sb, input->group) ? "normal" :
"no-super", input->group, input->blocks_count,
free_blocks_count, input->reserved_blocks);
if (group != sbi->s_groups_count)
ext3_warning(sb, __FUNCTION__,
"Cannot add at group %u (only %lu groups)",
input->group, sbi->s_groups_count);
else if ((start - le32_to_cpu(es->s_first_data_block)) %
EXT3_BLOCKS_PER_GROUP(sb))
ext3_warning(sb, __FUNCTION__, "Last group not full");
else if (input->reserved_blocks > input->blocks_count / 5)
ext3_warning(sb, __FUNCTION__, "Reserved blocks too high (%u)",
input->reserved_blocks);
else if (free_blocks_count < 0)
ext3_warning(sb, __FUNCTION__, "Bad blocks count %u",
input->blocks_count);
else if (!(bh = sb_bread(sb, end - 1)))
ext3_warning(sb, __FUNCTION__,
"Cannot read last block ("E3FSBLK")",
end - 1);
else if (outside(input->block_bitmap, start, end))
ext3_warning(sb, __FUNCTION__,
"Block bitmap not in group (block %u)",
input->block_bitmap);
else if (outside(input->inode_bitmap, start, end))
ext3_warning(sb, __FUNCTION__,
"Inode bitmap not in group (block %u)",
input->inode_bitmap);
else if (outside(input->inode_table, start, end) ||
outside(itend - 1, start, end))
ext3_warning(sb, __FUNCTION__,
"Inode table not in group (blocks %u-"E3FSBLK")",
input->inode_table, itend - 1);
else if (input->inode_bitmap == input->block_bitmap)
ext3_warning(sb, __FUNCTION__,
"Block bitmap same as inode bitmap (%u)",
input->block_bitmap);
else if (inside(input->block_bitmap, input->inode_table, itend))
ext3_warning(sb, __FUNCTION__,
"Block bitmap (%u) in inode table (%u-"E3FSBLK")",
input->block_bitmap, input->inode_table, itend-1);
else if (inside(input->inode_bitmap, input->inode_table, itend))
ext3_warning(sb, __FUNCTION__,
"Inode bitmap (%u) in inode table (%u-"E3FSBLK")",
input->inode_bitmap, input->inode_table, itend-1);
else if (inside(input->block_bitmap, start, metaend))
ext3_warning(sb, __FUNCTION__,
"Block bitmap (%u) in GDT table"
" ("E3FSBLK"-"E3FSBLK")",
input->block_bitmap, start