e2fsprogs/lib/ext2fs/initialize.c

545 lines
16 KiB
C
Raw Normal View History

1997-04-26 17:21:57 +04:00
/*
* initialize.c --- initialize a filesystem handle given superblock
* parameters. Used by mke2fs when initializing a filesystem.
*
1997-04-29 18:53:37 +04:00
* Copyright (C) 1994, 1995, 1996 Theodore Ts'o.
*
1997-04-29 20:17:09 +04:00
* %Begin-Header%
* This file may be redistributed under the terms of the GNU Library
* General Public License, version 2.
1997-04-29 20:17:09 +04:00
* %End-Header%
1997-04-26 17:21:57 +04:00
*/
#include "config.h"
1997-04-26 17:21:57 +04:00
#include <stdio.h>
#include <string.h>
#if HAVE_UNISTD_H
1997-04-26 17:21:57 +04:00
#include <unistd.h>
#endif
1997-04-26 17:21:57 +04:00
#include <fcntl.h>
#include <time.h>
#if HAVE_SYS_STAT_H
1997-04-26 17:21:57 +04:00
#include <sys/stat.h>
#endif
#if HAVE_SYS_TYPES_H
1997-04-26 17:21:57 +04:00
#include <sys/types.h>
#endif
1997-04-26 17:21:57 +04:00
Many files: inode.c (ext2fs_open_inode_scan): Initialize the group variables so that we don't need to call get_next_blockgroup() the first time around. Saves a bit of time, and prevents us from needing to assign -1 to current_group (which is an unsigned value). icount.c (insert_icount_el): Cast the estimated number of inodes from a float to an ino_t. alloc.c, alloc_tables.c, badlbocks.c, bb_compat.c, bb_inode.c, bitmaps.c, bitops.c, block.c, bmap.c, bmove.c, brel_ma.c, check_desc.c, closefs.c, cmp_bitmaps.c, dblist.c, dblist_dir.c, dir_iterate.c, dirblock.c, dupfs.c, expanddir.c, ext2fs.h, fileio.c, freefs.c, get_pathname.c, getsize.c, icount.c, initialize.c, inline.c, inode.c, irel_ma.c, ismounted.c, link.c, lookup.c, mkdir.c, namei.c, native.c, newdir.c, openfs.c, read_bb.c, read_bb_file.c, rs_bitmap.c, rw_bitmaps.c, swapfs.c, test_io.c, tst_badblocks.c, tst_getsize.c, tst_iscan.c, unix_io.c, unlink.c, valid_blk.c, version.c: If EXT2_FLAT_INCLUDES is defined, then assume all of the ext2-specific header files are in a flat directory. block.c, bmove.c, dirblock.c, fileio.c: Explicitly cast all assignments from void * to be compatible with C++. closefs.c (ext2fs_flush): Add a call to io_channel_flush() to make sure the contents of the disk are flushed to disk. dblist.c (ext2fs_add_dir_block): Change new to be new_entry to avoid C++ namespace clash. bitmaps.c (ext2fs_copy_bitmap): Change new to be new_map to avoid C++ namespace clash. ext2fs.h, bb_inode.c, block.c, bmove.c, brel.h, brel_ma.c, irel.h, irel_ma.c, dblist.c, dblist_dir.c, dir_iterate.c, ext2fsP.h, expanddir.c, get_pathname.c, inode.c, link.c, unlink.c: Change private to be priv_data (to avoid C++ namespace clash)
1998-01-19 17:47:53 +03:00
#include "ext2_fs.h"
1997-04-26 17:21:57 +04:00
#include "ext2fs.h"
2003-07-06 08:36:48 +04:00
#if defined(__linux__) && defined(EXT2_OS_LINUX)
1997-04-26 17:58:21 +04:00
#define CREATOR_OS EXT2_OS_LINUX
2003-07-06 08:36:48 +04:00
#else
#if defined(__GNU__) && defined(EXT2_OS_HURD)
1997-04-26 17:58:21 +04:00
#define CREATOR_OS EXT2_OS_HURD
2003-07-06 08:36:48 +04:00
#else
#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
1997-04-26 17:58:21 +04:00
#define CREATOR_OS EXT2_OS_FREEBSD
2003-07-06 08:36:48 +04:00
#else
#if defined(LITES) && defined(EXT2_OS_LITES)
1997-04-26 17:58:21 +04:00
#define CREATOR_OS EXT2_OS_LITES
#else
#define CREATOR_OS EXT2_OS_LINUX /* by default */
2003-07-06 08:36:48 +04:00
#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
/*
* Calculate the number of GDT blocks to reserve for online filesystem growth.
* The absolute maximum number of GDT blocks we can reserve is determined by
* the number of block pointers that can fit into a single block.
*/
static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs)
{
struct ext2_super_block *sb = fs->super;
unsigned long bpg = sb->s_blocks_per_group;
unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb);
unsigned long max_blocks = 0xffffffff;
unsigned long rsv_groups;
unsigned int rsv_gdb;
/* We set it at 1024x the current filesystem size, or
* the upper block count limit (2^32), whichever is lower.
*/
if (ext2fs_blocks_count(sb) < max_blocks / 1024)
max_blocks = ext2fs_blocks_count(sb) * 1024;
/*
* ext2fs_div64_ceil() is unnecessary because max_blocks is
* max _GDT_ blocks, which is limited to 32 bits.
*/
rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg);
rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks;
if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
#ifdef RES_GDT_DEBUG
printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n",
max_blocks, rsv_groups, rsv_gdb);
#endif
return rsv_gdb;
}
1997-04-26 17:21:57 +04:00
errcode_t ext2fs_initialize(const char *name, int flags,
struct ext2_super_block *param,
io_manager manager, ext2_filsys *ret_fs)
{
ext2_filsys fs;
errcode_t retval;
struct ext2_super_block *super;
2003-12-07 09:28:50 +03:00
unsigned int rem;
unsigned int overhead = 0;
unsigned int ipg;
dgrp_t i;
blk64_t free_blocks;
blk_t numblocks;
int rsv_gdt;
int csum_flag;
int bigalloc_flag;
int io_flags;
unsigned reserved_inos;
char *buf = 0;
char c;
mke2fs: recalculate the reserved blocks when the last BG is dropped mke2fs -m option can set reserved blocks ratio up to 50%. But if the last block group is not big enough to support the necessary data structures, it gets dropped, we have to recalculate the number of reserved blocks so that the reserved blocks matches the requested percentage. It also avoids a problem where if the user specifies a reserved blocks of 50%, and after the last partial block group was dropped, if the number of reserved blocks is greater than 50%, e2fsck will complain. Steps to reproduce: 1. Create a FS which has the overhead for the last BG and specify 50 % for reserved blocks ratio # mke2fs -m 50 -t ext4 DEV 1025M mke2fs 1.42.5 (29-Jul-2012) warning: 256 blocks unused. Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 656640 inodes, 2621440 blocks 1310848 blocks (50.00%) reserved for the super user ~~~~~~~ <-- Reserved blocks exceed 50% of FS blocks count! 2. e2fsck outputs filesystem corruption # e2fsck DEV e2fsck 1.42.5 (29-Jul-2012) Corruption found in superblock. (r_blocks_count = 1310848). The superblock could not be read or does not describe a correct ext2 filesystem. If the device is valid and it really contains an ext2 filesystem (and not swap or ufs or something else), then the superblock is corrupt, and you might try running e2fsck with an alternate superblock: e2fsck -b 32768 <device> Signed-off-by: Akira Fujita <a-fujita@rs.jp.ne.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2012-08-30 15:16:01 +04:00
double reserved_ratio;
1997-04-26 17:21:57 +04:00
if (!param || !ext2fs_blocks_count(param))
return EXT2_ET_INVALID_ARGUMENT;
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
if (retval)
return retval;
1997-04-26 17:21:57 +04:00
memset(fs, 0, sizeof(struct struct_ext2_filsys));
1997-04-26 17:34:30 +04:00
fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
fs->flags = flags | EXT2_FLAG_RW;
fs->umask = 022;
fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
#ifdef WORDS_BIGENDIAN
fs->flags |= EXT2_FLAG_SWAP_BYTES;
#endif
io_flags = IO_FLAG_RW;
if (flags & EXT2_FLAG_EXCLUSIVE)
io_flags |= IO_FLAG_EXCLUSIVE;
if (flags & EXT2_FLAG_DIRECT_IO)
io_flags |= IO_FLAG_DIRECT_IO;
retval = manager->open(name, io_flags, &fs->io);
1997-04-26 17:21:57 +04:00
if (retval)
goto cleanup;
fs->image_io = fs->io;
fs->io->app_data = fs;
retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
if (retval)
1997-04-26 17:21:57 +04:00
goto cleanup;
1997-04-26 17:21:57 +04:00
strcpy(fs->device_name, name);
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
if (retval)
1997-04-26 17:21:57 +04:00
goto cleanup;
fs->super = super;
1997-04-26 17:21:57 +04:00
memset(super, 0, SUPERBLOCK_SIZE);
#define set_field(field, default) (super->field = param->field ? \
param->field : (default))
#define assign_field(field) (super->field = param->field)
1997-04-26 17:21:57 +04:00
super->s_magic = EXT2_SUPER_MAGIC;
super->s_state = EXT2_VALID_FS;
bigalloc_flag = ext2fs_has_feature_bigalloc(param);
assign_field(s_log_block_size);
if (bigalloc_flag) {
set_field(s_log_cluster_size, super->s_log_block_size+4);
if (super->s_log_block_size > super->s_log_cluster_size) {
retval = EXT2_ET_INVALID_ARGUMENT;
goto cleanup;
}
} else
super->s_log_cluster_size = super->s_log_block_size;
set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1);
set_field(s_max_mnt_count, 0);
1997-04-26 17:21:57 +04:00
set_field(s_errors, EXT2_ERRORS_DEFAULT);
1997-04-30 01:26:48 +04:00
set_field(s_feature_compat, 0);
set_field(s_feature_incompat, 0);
set_field(s_feature_ro_compat, 0);
set_field(s_default_mount_opts, 0);
set_field(s_first_meta_bg, 0);
set_field(s_raid_stride, 0); /* default stride size: 0 */
set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */
set_field(s_log_groups_per_flex, 0);
set_field(s_flags, 0);
assign_field(s_backup_bgs[0]);
assign_field(s_backup_bgs[1]);
if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) {
retval = EXT2_ET_UNSUPP_FEATURE;
goto cleanup;
}
if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
retval = EXT2_ET_RO_UNSUPP_FEATURE;
goto cleanup;
}
1997-04-26 18:48:50 +04:00
set_field(s_rev_level, EXT2_GOOD_OLD_REV);
if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
int extra_isize = sizeof(struct ext2_inode_large) -
EXT2_GOOD_OLD_INODE_SIZE;
set_field(s_min_extra_isize, extra_isize);
set_field(s_want_extra_isize, extra_isize);
}
} else {
super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
1997-04-26 18:48:50 +04:00
}
set_field(s_checkinterval, 0);
super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);
1997-04-26 17:21:57 +04:00
1997-04-26 17:58:21 +04:00
super->s_creator_os = CREATOR_OS;
1997-04-26 17:34:30 +04:00
fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super);
fs->cluster_ratio_bits = super->s_log_cluster_size -
super->s_log_block_size;
if (bigalloc_flag) {
unsigned long long bpg;
if (param->s_blocks_per_group &&
param->s_clusters_per_group &&
((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) !=
param->s_blocks_per_group)) {
retval = EXT2_ET_INVALID_ARGUMENT;
goto cleanup;
}
if (param->s_clusters_per_group)
assign_field(s_clusters_per_group);
else if (param->s_blocks_per_group)
super->s_clusters_per_group =
param->s_blocks_per_group /
EXT2FS_CLUSTER_RATIO(fs);
else if (super->s_log_cluster_size + 15 < 32)
super->s_clusters_per_group = fs->blocksize * 8;
else
super->s_clusters_per_group = (fs->blocksize - 1) * 8;
if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super))
super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super);
bpg = EXT2FS_C2B(fs,
(unsigned long long) super->s_clusters_per_group);
if (bpg >= (((unsigned long long) 1) << 32)) {
retval = EXT2_ET_INVALID_ARGUMENT;
goto cleanup;
}
super->s_blocks_per_group = bpg;
} else {
set_field(s_blocks_per_group, fs->blocksize * 8);
if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
super->s_clusters_per_group = super->s_blocks_per_group;
}
ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) &
~((blk64_t) EXT2FS_CLUSTER_MASK(fs)));
ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param));
if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) {
retval = EXT2_ET_INVALID_ARGUMENT;
1997-04-26 17:34:30 +04:00
goto cleanup;
}
1997-04-26 17:21:57 +04:00
set_field(s_mmp_update_interval, 0);
/*
* If we're creating an external journal device, we don't need
* to bother with the rest.
*/
if (ext2fs_has_feature_journal_dev(super)) {
fs->group_desc_count = 0;
ext2fs_mark_super_dirty(fs);
*ret_fs = fs;
return 0;
}
1997-04-26 17:21:57 +04:00
retry:
fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil(
ext2fs_blocks_count(super) - super->s_first_data_block,
EXT2_BLOCKS_PER_GROUP(super));
if (fs->group_desc_count == 0) {
retval = EXT2_ET_TOOSMALL;
goto cleanup;
}
debugfs, e2fsck: fix s_desc_size handling The s_desc_size in the superblock specifies the group descriptor size in bytes, but in various places the EXT4_FEATURE_INCOMPAT_64BIT flag implies that the descriptor size is EXT2_MIN_DESC_SIZE_64BIT (64 bytes) instead of checking the actual size. In other places, the s_desc_size field is used without checking for INCOMPAT_64BIT. In the case of ext2fs_group_desc() the s_desc_size was being ignored, and assumed to be sizeof(struct ext4_group_desc), which would result in garbage for any but the first group descriptor. Similarly, in ext2fs_group_desc_csum() and print_csum() they assumed that the maximum group descriptor size was sizeof(struct ext4_group_desc). Fix these functions to use the actual superblock s_desc_size if INCOMPAT_64BIT. Conversely, in ext2fs_swap_group_desc2() s_desc_size was used without checking for INCOMPAT_64BIT being set. The e2fsprogs behaviour is different than that of the kernel, which always checks INCOMPAT_64BIT, and only uses s_desc_size to determine the offset of group descriptors and what range of bytes to checksum. Allow specifying the s_desc_size field at mke2fs time with the "-E desc_size=NNN" option. Allow a power-of-two s_desc_size value up to s_blocksize if INCOMPAT_64BIT is specified. This is not expected to be used by regular users at this time, so it is not currently documented in the mke2fs usage or man page. Add m_desc_size_128, f_desc_size_128, and f_desc_bad test cases to verify mke2fs and e2fsck handling of larger group descriptor sizes. Signed-off-by: Andreas Dilger <adilger@dilger.ca> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2013-12-24 01:04:46 +04:00
set_field(s_desc_size,
ext2fs_has_feature_64bit(super) ?
debugfs, e2fsck: fix s_desc_size handling The s_desc_size in the superblock specifies the group descriptor size in bytes, but in various places the EXT4_FEATURE_INCOMPAT_64BIT flag implies that the descriptor size is EXT2_MIN_DESC_SIZE_64BIT (64 bytes) instead of checking the actual size. In other places, the s_desc_size field is used without checking for INCOMPAT_64BIT. In the case of ext2fs_group_desc() the s_desc_size was being ignored, and assumed to be sizeof(struct ext4_group_desc), which would result in garbage for any but the first group descriptor. Similarly, in ext2fs_group_desc_csum() and print_csum() they assumed that the maximum group descriptor size was sizeof(struct ext4_group_desc). Fix these functions to use the actual superblock s_desc_size if INCOMPAT_64BIT. Conversely, in ext2fs_swap_group_desc2() s_desc_size was used without checking for INCOMPAT_64BIT being set. The e2fsprogs behaviour is different than that of the kernel, which always checks INCOMPAT_64BIT, and only uses s_desc_size to determine the offset of group descriptors and what range of bytes to checksum. Allow specifying the s_desc_size field at mke2fs time with the "-E desc_size=NNN" option. Allow a power-of-two s_desc_size value up to s_blocksize if INCOMPAT_64BIT is specified. This is not expected to be used by regular users at this time, so it is not currently documented in the mke2fs usage or man page. Add m_desc_size_128, f_desc_size_128, and f_desc_bad test cases to verify mke2fs and e2fsck handling of larger group descriptor sizes. Signed-off-by: Andreas Dilger <adilger@dilger.ca> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2013-12-24 01:04:46 +04:00
EXT2_MIN_DESC_SIZE_64BIT : 0);
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
EXT2_DESC_PER_BLOCK(super));
1997-04-26 17:21:57 +04:00
i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
if (ext2fs_has_feature_64bit(super) &&
(ext2fs_blocks_count(super) / i) > (1ULL << 32))
set_field(s_inodes_count, ~0U);
else
set_field(s_inodes_count, ext2fs_blocks_count(super) / i);
1997-04-26 17:21:57 +04:00
/*
* Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
* that we have enough inodes for the filesystem(!)
*/
if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
1997-04-26 17:21:57 +04:00
/*
* There should be at least as many inodes as the user
* requested. Figure out how many inodes per group that
1997-04-26 17:58:21 +04:00
* should be. But make sure that we don't allocate more than
* one bitmap's worth of inodes each group.
1997-04-26 17:21:57 +04:00
*/
ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
if (ipg > fs->blocksize * 8) {
if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
/* Try again with slightly different parameters */
super->s_blocks_per_group -= 8;
ext2fs_blocks_count_set(super,
ext2fs_blocks_count(param));
super->s_clusters_per_group = super->s_blocks_per_group;
goto retry;
} else {
retval = EXT2_ET_TOO_MANY_INODES;
goto cleanup;
}
}
2003-12-07 09:28:50 +03:00
if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
ipg = EXT2_MAX_INODES_PER_GROUP(super);
ipg_retry:
super->s_inodes_per_group = ipg;
1997-04-26 17:21:57 +04:00
/*
* Make sure the number of inodes per group completely fills
* the inode table blocks in the descriptor. If not, add some
* additional inodes/group. Waste not, want not...
*/
1997-04-26 18:48:50 +04:00
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
EXT2_INODE_SIZE(super)) +
EXT2_BLOCK_SIZE(super) - 1) /
EXT2_BLOCK_SIZE(super));
super->s_inodes_per_group = ((fs->inode_blocks_per_group *
EXT2_BLOCK_SIZE(super)) /
EXT2_INODE_SIZE(super));
/*
* Finally, make sure the number of inodes per group is a
* multiple of 8. This is needed to simplify the bitmap
* splicing code.
*/
if (super->s_inodes_per_group < 8)
super->s_inodes_per_group = 8;
1997-04-26 18:48:50 +04:00
super->s_inodes_per_group &= ~7;
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
EXT2_INODE_SIZE(super)) +
EXT2_BLOCK_SIZE(super) - 1) /
EXT2_BLOCK_SIZE(super));
1997-04-26 17:21:57 +04:00
/*
* adjust inode count to reflect the adjusted inodes_per_group
*/
if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) {
ipg--;
goto ipg_retry;
}
1997-04-26 17:21:57 +04:00
super->s_inodes_count = super->s_inodes_per_group *
fs->group_desc_count;
super->s_free_inodes_count = super->s_inodes_count;
/*
* check the number of reserved group descriptor table blocks
*/
if (ext2fs_has_feature_resize_inode(super))
rsv_gdt = calc_reserved_gdt_blocks(fs);
else
rsv_gdt = 0;
set_field(s_reserved_gdt_blocks, rsv_gdt);
if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
retval = EXT2_ET_RES_GDT_BLOCKS;
goto cleanup;
}
1997-04-29 21:57:00 +04:00
/*
* Calculate the maximum number of bookkeeping blocks per
* group. It includes the superblock, the block group
* descriptors, the block bitmap, the inode bitmap, the inode
* table, and the reserved gdt blocks.
1997-04-29 21:57:00 +04:00
*/
overhead = (int) (3 + fs->inode_blocks_per_group +
super->s_reserved_gdt_blocks);
/* Enable meta_bg if we'd lose more than 3/4 of a BG to GDT blocks. */
if (super->s_reserved_gdt_blocks + fs->desc_blocks >
super->s_blocks_per_group * 3 / 4)
ext2fs_set_feature_meta_bg(fs->super);
if (ext2fs_has_feature_meta_bg(fs->super))
overhead++;
else
overhead += fs->desc_blocks;
/* This can only happen if the user requested too many inodes */
if (overhead > super->s_blocks_per_group) {
retval = EXT2_ET_TOO_MANY_INODES;
goto cleanup;
}
1997-04-26 17:21:57 +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. We need to recalculate the overhead for the last block
* group, since it might or might not have a superblock
* backup.
1997-04-26 17:21:57 +04:00
*/
overhead = (int) (2 + fs->inode_blocks_per_group);
if (ext2fs_bg_has_super(fs, fs->group_desc_count - 1))
overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) %
2003-12-07 09:28:50 +03:00
super->s_blocks_per_group);
if ((fs->group_desc_count == 1) && rem && (rem < overhead)) {
retval = EXT2_ET_TOOSMALL;
goto cleanup;
}
1997-04-26 17:21:57 +04:00
if (rem && (rem < overhead+50)) {
ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) -
rem);
mke2fs: recalculate the reserved blocks when the last BG is dropped mke2fs -m option can set reserved blocks ratio up to 50%. But if the last block group is not big enough to support the necessary data structures, it gets dropped, we have to recalculate the number of reserved blocks so that the reserved blocks matches the requested percentage. It also avoids a problem where if the user specifies a reserved blocks of 50%, and after the last partial block group was dropped, if the number of reserved blocks is greater than 50%, e2fsck will complain. Steps to reproduce: 1. Create a FS which has the overhead for the last BG and specify 50 % for reserved blocks ratio # mke2fs -m 50 -t ext4 DEV 1025M mke2fs 1.42.5 (29-Jul-2012) warning: 256 blocks unused. Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) Stride=0 blocks, Stripe width=0 blocks 656640 inodes, 2621440 blocks 1310848 blocks (50.00%) reserved for the super user ~~~~~~~ <-- Reserved blocks exceed 50% of FS blocks count! 2. e2fsck outputs filesystem corruption # e2fsck DEV e2fsck 1.42.5 (29-Jul-2012) Corruption found in superblock. (r_blocks_count = 1310848). The superblock could not be read or does not describe a correct ext2 filesystem. If the device is valid and it really contains an ext2 filesystem (and not swap or ufs or something else), then the superblock is corrupt, and you might try running e2fsck with an alternate superblock: e2fsck -b 32768 <device> Signed-off-by: Akira Fujita <a-fujita@rs.jp.ne.com> Signed-off-by: Theodore Ts'o <tytso@mit.edu>
2012-08-30 15:16:01 +04:00
/*
* If blocks count is changed, we need to recalculate
* reserved blocks count not to exceed 50%.
*/
reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) /
ext2fs_blocks_count(param);
ext2fs_r_blocks_count_set(super, reserved_ratio *
ext2fs_blocks_count(super) / 100.0);
1997-04-26 17:21:57 +04:00
goto retry;
}
/*
* At this point we know how big the filesystem will be. So
* we can do any and all allocations that depend on the block
* count.
*/
/* Set up the locations of the backup superblocks */
if (ext2fs_has_feature_sparse_super2(super)) {
if (super->s_backup_bgs[0] >= fs->group_desc_count)
super->s_backup_bgs[0] = fs->group_desc_count - 1;
if (super->s_backup_bgs[1] >= fs->group_desc_count)
super->s_backup_bgs[1] = fs->group_desc_count - 1;
if (super->s_backup_bgs[0] == super->s_backup_bgs[1])
super->s_backup_bgs[1] = 0;
if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) {
__u32 t = super->s_backup_bgs[0];
super->s_backup_bgs[0] = super->s_backup_bgs[1];
super->s_backup_bgs[1] = t;
}
}
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
if (retval)
1997-04-26 17:34:30 +04:00
goto cleanup;
strcpy(buf, "block bitmap for ");
strcat(buf, fs->device_name);
retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map);
1997-04-26 17:21:57 +04:00
if (retval)
goto cleanup;
strcpy(buf, "inode bitmap for ");
strcat(buf, fs->device_name);
1997-04-29 19:29:49 +04:00
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
1997-04-26 17:21:57 +04:00
if (retval)
goto cleanup;
ext2fs_free_mem(&buf);
1997-04-26 17:34:30 +04:00
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
&fs->group_desc);
if (retval)
1997-04-26 17:21:57 +04:00
goto cleanup;
memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
1997-04-26 17:21:57 +04:00
1997-04-26 17:34:30 +04:00
/*
* Reserve the superblock and group descriptors for each
* group, and fill in the correct group statistics for group.
* Note that although the block bitmap, inode bitmap, and
* inode table have not been allocated (and in fact won't be
* by this routine), they are accounted for nevertheless.
*
* If FLEX_BG meta-data grouping is used, only account for the
* superblock and group descriptors (the inode tables and
* bitmaps will be accounted for when allocated).
1997-04-26 17:34:30 +04:00
*/
free_blocks = 0;
csum_flag = ext2fs_has_group_desc_csum(fs);
reserved_inos = super->s_first_ino;
1997-04-26 17:21:57 +04:00
for (i = 0; i < fs->group_desc_count; i++) {
/*
* Don't set the BLOCK_UNINIT group for the last group
* because the block bitmap needs to be padded.
*/
if (csum_flag) {
if (i != fs->group_desc_count - 1)
ext2fs_bg_flags_set(fs, i,
EXT2_BG_BLOCK_UNINIT);
ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
numblocks = super->s_inodes_per_group;
if (reserved_inos) {
if (numblocks > reserved_inos) {
numblocks -= reserved_inos;
reserved_inos = 0;
} else {
reserved_inos -= numblocks;
numblocks = 0;
}
}
ext2fs_bg_itable_unused_set(fs, i, numblocks);
}
numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
if (fs->super->s_log_groups_per_flex)
numblocks += 2 + fs->inode_blocks_per_group;
free_blocks += numblocks;
ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group);
ext2fs_bg_used_dirs_count_set(fs, i, 0);
ext2fs_group_desc_csum_set(fs, i);
1997-04-26 17:21:57 +04:00
}
free_blocks &= ~EXT2FS_CLUSTER_MASK(fs);
ext2fs_free_blocks_count_set(super, free_blocks);
c = (char) 255;
if (((int) c) == -1) {
super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
} else {
super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
}
1997-04-26 17:21:57 +04:00
ext2fs_mark_super_dirty(fs);
ext2fs_mark_bb_dirty(fs);
ext2fs_mark_ib_dirty(fs);
1997-04-26 17:21:57 +04:00
io_channel_set_blksize(fs->io, fs->blocksize);
*ret_fs = fs;
return 0;
cleanup:
free(buf);
1997-04-26 17:21:57 +04:00
ext2fs_free(fs);
return retval;
}