ext4: make ext4_block_in_group() much more efficient
Currently in when getting the block group number for a particular block in ext4_block_in_group() we're using ext4_get_group_no_and_offset() which uses do_div() to get the block group and the remainer which is offset within the group. We don't need all of that in ext4_block_in_group() as we only need to figure out the group number. This commit changes ext4_block_in_group() to calculate group number directly. This shows as a big improvement with regards to cpu utilization. Measuring fallocate -l 15T on fresh file system with perf showed that 23% of cpu time was spend in the ext4_get_group_no_and_offset(). With this change it completely disappears from the list only bumping the occurrence of ext4_init_block_bitmap() which is the biggest user of ext4_block_in_group() by 4%. As the result of this change on my system the fallocate call was approx. 10% faster. However since there is '-g' option in mkfs which allow us setting different groups size (mostly for developers) I've introduced new per file system flag whether we have a standard block group size or not. The flag is used to determine whether we can use the bit shift optimization or not. Signed-off-by: Lukas Czerner <lczerner@redhat.com> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
This commit is contained in:
parent
a75ae78f08
commit
689110098c
|
@ -49,14 +49,24 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr,
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block,
|
/*
|
||||||
ext4_group_t block_group)
|
* Check whether the 'block' lives within the 'block_group'. Returns 1 if so
|
||||||
|
* and 0 otherwise.
|
||||||
|
*/
|
||||||
|
static inline int ext4_block_in_group(struct super_block *sb,
|
||||||
|
ext4_fsblk_t block,
|
||||||
|
ext4_group_t block_group)
|
||||||
{
|
{
|
||||||
ext4_group_t actual_group;
|
ext4_group_t actual_group;
|
||||||
ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
|
|
||||||
if (actual_group == block_group)
|
if (test_opt2(sb, STD_GROUP_SIZE))
|
||||||
return 1;
|
actual_group =
|
||||||
return 0;
|
(le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) +
|
||||||
|
block) >>
|
||||||
|
(EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3);
|
||||||
|
else
|
||||||
|
ext4_get_group_no_and_offset(sb, block, &actual_group, NULL);
|
||||||
|
return (actual_group == block_group) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return the number of clusters used for file system metadata; this
|
/* Return the number of clusters used for file system metadata; this
|
||||||
|
|
|
@ -949,7 +949,7 @@ struct ext4_inode_info {
|
||||||
#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
|
#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mount flags
|
* Mount flags set via mount options or defaults
|
||||||
*/
|
*/
|
||||||
#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
|
#define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */
|
||||||
#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
|
#define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */
|
||||||
|
@ -981,8 +981,16 @@ struct ext4_inode_info {
|
||||||
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
|
#define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */
|
||||||
#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
|
#define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mount flags set either automatically (could not be set by mount option)
|
||||||
|
* based on per file system feature or property or in special cases such as
|
||||||
|
* distinguishing between explicit mount option definition and default.
|
||||||
|
*/
|
||||||
#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly
|
#define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly
|
||||||
specified delalloc */
|
specified delalloc */
|
||||||
|
#define EXT4_MOUNT2_STD_GROUP_SIZE 0x00000002 /* We have standard group
|
||||||
|
size of blocksize * 8
|
||||||
|
blocks */
|
||||||
|
|
||||||
#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \
|
#define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \
|
||||||
~EXT4_MOUNT_##opt
|
~EXT4_MOUNT_##opt
|
||||||
|
|
|
@ -3529,6 +3529,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
||||||
sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
|
sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb));
|
||||||
sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
|
sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb));
|
||||||
|
|
||||||
|
/* Do we have standard group size of blocksize * 8 blocks ? */
|
||||||
|
if (sbi->s_blocks_per_group == blocksize << 3)
|
||||||
|
set_opt2(sb, STD_GROUP_SIZE);
|
||||||
|
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
|
sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]);
|
||||||
sbi->s_def_hash_version = es->s_def_hash_version;
|
sbi->s_def_hash_version = es->s_def_hash_version;
|
||||||
|
|
Loading…
Reference in New Issue