Add flex_bg/meta_bg features RW support.

Reviewed by:    pfg
MFC after:      6 months

Differential Revision:    https://reviews.freebsd.org/D13964
This commit is contained in:
fsu 2018-01-29 21:54:13 +00:00
parent 59f27534cc
commit 0a2aa6292e
3 changed files with 110 additions and 45 deletions

View File

@ -755,49 +755,68 @@ ext2_hashalloc(struct inode *ip, int cg, long pref, int size,
}
static unsigned long
ext2_cg_num_gdb(struct m_ext2fs *fs, int cg)
ext2_cg_number_gdb_nometa(struct m_ext2fs *fs, int cg)
{
int gd_per_block, metagroup, first, last;
gd_per_block = fs->e2fs_bsize / sizeof(struct ext2_gd);
metagroup = cg / gd_per_block;
first = metagroup * gd_per_block;
last = first + gd_per_block - 1;
if (!ext2_cg_has_sb(fs, cg))
return (0);
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) ||
metagroup < fs->e2fs->e3fs_first_meta_bg) {
if (!ext2_cg_has_sb(fs, cg))
return (0);
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG))
return (fs->e2fs->e3fs_first_meta_bg);
return (fs->e2fs_gdbcount);
}
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG))
return (fs->e2fs->e3fs_first_meta_bg);
return ((fs->e2fs_gcount + EXT2_DESCS_PER_BLOCK(fs) - 1) /
EXT2_DESCS_PER_BLOCK(fs));
}
static unsigned long
ext2_cg_number_gdb_meta(struct m_ext2fs *fs, int cg)
{
unsigned long metagroup;
int first, last;
metagroup = cg / EXT2_DESCS_PER_BLOCK(fs);
first = metagroup * EXT2_DESCS_PER_BLOCK(fs);
last = first + EXT2_DESCS_PER_BLOCK(fs) - 1;
if (cg == first || cg == first + 1 || cg == last)
return (1);
return (0);
return (0);
}
static unsigned long
ext2_cg_number_gdb(struct m_ext2fs *fs, int cg)
{
unsigned long first_meta_bg, metagroup;
first_meta_bg = fs->e2fs->e3fs_first_meta_bg;
metagroup = cg / EXT2_DESCS_PER_BLOCK(fs);
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) ||
metagroup < first_meta_bg)
return (ext2_cg_number_gdb_nometa(fs, cg));
return ext2_cg_number_gdb_meta(fs, cg);
}
static int
ext2_num_base_meta_blocks(struct m_ext2fs *fs, int cg)
ext2_number_base_meta_blocks(struct m_ext2fs *fs, int cg)
{
int num, gd_per_block;
int number;
gd_per_block = fs->e2fs_bsize / sizeof(struct ext2_gd);
num = ext2_cg_has_sb(fs, cg);
number = ext2_cg_has_sb(fs, cg);
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) ||
cg < fs->e2fs->e3fs_first_meta_bg * gd_per_block) {
if (num) {
num += ext2_cg_num_gdb(fs, cg);
num += fs->e2fs->e2fs_reserved_ngdb;
cg < fs->e2fs->e3fs_first_meta_bg * EXT2_DESCS_PER_BLOCK(fs)) {
if (number) {
number += ext2_cg_number_gdb(fs, cg);
number += fs->e2fs->e2fs_reserved_ngdb;
}
} else {
num += ext2_cg_num_gdb(fs, cg);
number += ext2_cg_number_gdb(fs, cg);
}
return (num);
return (number);
}
static void
@ -814,6 +833,20 @@ ext2_mark_bitmap_end(int start_bit, int end_bit, char *bitmap)
memset(bitmap + (i >> 3), 0xff, (end_bit - i) >> 3);
}
static int
ext2_get_group_number(struct m_ext2fs *fs, e4fs_daddr_t block)
{
return ((block - fs->e2fs->e2fs_first_dblock) / fs->e2fs_bsize);
}
static int
ext2_block_in_group(struct m_ext2fs *fs, e4fs_daddr_t block, int cg)
{
return ((ext2_get_group_number(fs, block) == cg) ? 1 : 0);
}
static int
ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp)
{
@ -825,7 +858,7 @@ ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp)
memset(bp->b_data, 0, fs->e2fs_bsize);
bit_max = ext2_num_base_meta_blocks(fs, cg);
bit_max = ext2_number_base_meta_blocks(fs, cg);
if ((bit_max >> 3) >= fs->e2fs_bsize)
return (EINVAL);
@ -837,12 +870,12 @@ ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp)
/* Set bits for block and inode bitmaps, and inode table. */
tmp = e2fs_gd_get_b_bitmap(&fs->e2fs_gd[cg]);
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) ||
cg == dtogd(fs, tmp))
ext2_block_in_group(fs, tmp, cg))
setbit(bp->b_data, tmp - start);
tmp = e2fs_gd_get_i_bitmap(&fs->e2fs_gd[cg]);
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) ||
cg == dtogd(fs, tmp))
ext2_block_in_group(fs, tmp, cg))
setbit(bp->b_data, tmp - start);
tmp = e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]);
@ -850,7 +883,7 @@ ext2_cg_block_bitmap_init(struct m_ext2fs *fs, int cg, struct buf *bp)
while( tmp < e2fs_gd_get_i_tables(&fs->e2fs_gd[cg]) +
fs->e2fs->e2fs_ipg / inodes_per_block ) {
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) ||
cg == dtogd(fs, tmp))
ext2_block_in_group(fs, tmp, cg))
setbit(bp->b_data, tmp - start);
tmp++;
}

View File

@ -154,7 +154,8 @@ ext2_mount(struct mount *mp)
if (mp->mnt_flag & MNT_FORCE)
flags |= FORCECLOSE;
error = ext2_flushfiles(mp, flags, td);
if (error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) {
if (error == 0 && fs->e2fs_wasvalid &&
ext2_cgupdate(ump, MNT_WAIT) == 0) {
fs->e2fs->e2fs_state |= E2FS_ISCLEAN;
ext2_sbupdate(ump, MNT_WAIT);
}
@ -318,6 +319,36 @@ ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly)
return (0);
}
static e4fs_daddr_t
cg_location(struct m_ext2fs *fs, int number)
{
int cg, descpb, logical_sb, has_super = 0;
/*
* Adjust logical superblock block number.
* Godmar thinks: if the blocksize is greater than 1024, then
* the superblock is logically part of block zero.
*/
logical_sb = fs->e2fs_bsize > SBSIZE ? 0 : 1;
if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) ||
number < fs->e2fs->e3fs_first_meta_bg)
return (logical_sb + number + 1);
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT))
descpb = fs->e2fs_bsize / sizeof(struct ext2_gd);
else
descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE;
cg = descpb * number;
if (ext2_cg_has_sb(fs, cg))
has_super = 1;
return (has_super + cg * (e4fs_daddr_t)EXT2_BLOCKS_PER_GROUP(fs) +
fs->e2fs->e2fs_first_dblock);
}
/*
* This computes the fields of the m_ext2fs structure from the
* data in the ext2fs structure read in.
@ -328,7 +359,6 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
{
int g_count = 0, error;
int i, j;
int logic_sb_block = 1; /* XXX for now */
struct buf *bp;
uint32_t e2fs_descpb, e2fs_gdbcount_alloc;
@ -385,6 +415,12 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
es->e3fs_desc_size);
return (EINVAL);
}
/* Check for group size */
if (fs->e2fs_bpg != fs->e2fs_bsize * 8) {
printf("ext2fs: non-standard group size unsupported %d\n",
fs->e2fs_bpg);
return (EINVAL);
}
fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs);
fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb;
@ -405,16 +441,9 @@ compute_sb_data(struct vnode *devvp, struct ext2fs *es,
fs->e2fs_contigdirs = malloc(fs->e2fs_gcount *
sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO);
/*
* Adjust logic_sb_block.
* Godmar thinks: if the blocksize is greater than 1024, then
* the superblock is logically part of block zero.
*/
if (fs->e2fs_bsize > SBSIZE)
logic_sb_block = 0;
for (i = 0; i < fs->e2fs_gdbcount; i++) {
error = bread(devvp,
fsbtodb(fs, logic_sb_block + i + 1),
fsbtodb(fs, cg_location(fs, i)),
fs->e2fs_bsize, NOCRED, &bp);
if (error) {
free(fs->e2fs_contigdirs, M_EXT2MNT);
@ -1151,8 +1180,8 @@ ext2_cgupdate(struct ext2mount *mp, int waitfor)
for (i = 0; i < fs->e2fs_gdbcount; i++) {
bp = getblk(mp->um_devvp, fsbtodb(fs,
fs->e2fs->e2fs_first_dblock +
1 /* superblock */ + i), fs->e2fs_bsize, 0, 0, 0);
cg_location(fs, i)),
fs->e2fs_bsize, 0, 0, 0);
if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) {
memcpy(bp->b_data, &fs->e2fs_gd[
i * fs->e2fs_bsize / sizeof(struct ext2_gd)],

View File

@ -334,12 +334,12 @@ static const struct ext2_feature incompat[] = {
EXT2F_ROCOMPAT_HUGE_FILE | \
EXT2F_ROCOMPAT_EXTRA_ISIZE)
#define EXT2F_INCOMPAT_SUPP (EXT2F_INCOMPAT_FTYPE | \
EXT2F_INCOMPAT_META_BG | \
EXT2F_INCOMPAT_EXTENTS | \
EXT2F_INCOMPAT_64BIT | \
EXT2F_INCOMPAT_CSUM_SEED)
#define EXT4F_RO_INCOMPAT_SUPP (EXT2F_INCOMPAT_RECOVER | \
EXT2F_INCOMPAT_FLEX_BG | \
EXT2F_INCOMPAT_META_BG )
EXT2F_INCOMPAT_CSUM_SEED)
#define EXT4F_RO_INCOMPAT_SUPP EXT2F_INCOMPAT_RECOVER
/* Assume that user mode programs are passing in an ext2fs superblock, not
* a kernel struct super_block. This will allow us to call the feature-test
@ -423,5 +423,8 @@ struct ext2_gd {
* Macro-instructions used to manage group descriptors
*/
#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->e2fs_bpg)
#define EXT2_DESCS_PER_BLOCK(s) (EXT2_HAS_INCOMPAT_FEATURE((s), \
EXT2F_INCOMPAT_64BIT) ? ((s)->e2fs_bsize / sizeof(struct ext2_gd)) : \
((s)->e2fs_bsize / E2FS_REV0_GD_SIZE))
#endif /* !_FS_EXT2FS_EXT2FS_H_ */