diff options
author | Lukas Czerner <lczerner@redhat.com> | 2013-04-03 22:12:52 -0400 |
---|---|---|
committer | Theodore Ts'o <tytso@mit.edu> | 2013-04-03 22:12:52 -0400 |
commit | 689110098c7df10fab8800d3bf8e727c21f426fb (patch) | |
tree | 4115e575da8b49716e358ebd2459095863ad00e1 /fs/ext4 | |
parent | a75ae78f087f933ab3432e98bb4dbbf2196cf6d5 (diff) |
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>
Diffstat (limited to 'fs/ext4')
-rw-r--r-- | fs/ext4/balloc.c | 22 | ||||
-rw-r--r-- | fs/ext4/ext4.h | 10 | ||||
-rw-r--r-- | fs/ext4/super.c | 4 |
3 files changed, 29 insertions, 7 deletions
diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 92e68b33fffd..d6babf94907e 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c | |||
@@ -49,14 +49,24 @@ void ext4_get_group_no_and_offset(struct super_block *sb, ext4_fsblk_t blocknr, | |||
49 | 49 | ||
50 | } | 50 | } |
51 | 51 | ||
52 | static int ext4_block_in_group(struct super_block *sb, ext4_fsblk_t block, | 52 | /* |
53 | ext4_group_t block_group) | 53 | * Check whether the 'block' lives within the 'block_group'. Returns 1 if so |
54 | * and 0 otherwise. | ||
55 | */ | ||
56 | static inline int ext4_block_in_group(struct super_block *sb, | ||
57 | ext4_fsblk_t block, | ||
58 | ext4_group_t block_group) | ||
54 | { | 59 | { |
55 | ext4_group_t actual_group; | 60 | ext4_group_t actual_group; |
56 | ext4_get_group_no_and_offset(sb, block, &actual_group, NULL); | 61 | |
57 | if (actual_group == block_group) | 62 | if (test_opt2(sb, STD_GROUP_SIZE)) |
58 | return 1; | 63 | actual_group = |
59 | return 0; | 64 | (le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block) + |
65 | block) >> | ||
66 | (EXT4_BLOCK_SIZE_BITS(sb) + EXT4_CLUSTER_BITS(sb) + 3); | ||
67 | else | ||
68 | ext4_get_group_no_and_offset(sb, block, &actual_group, NULL); | ||
69 | return (actual_group == block_group) ? 1 : 0; | ||
60 | } | 70 | } |
61 | 71 | ||
62 | /* Return the number of clusters used for file system metadata; this | 72 | /* Return the number of clusters used for file system metadata; this |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 73f3e60f7078..cc58aa8e9869 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
@@ -949,7 +949,7 @@ struct ext4_inode_info { | |||
949 | #define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */ | 949 | #define EXT2_FLAGS_TEST_FILESYS 0x0004 /* to test development code */ |
950 | 950 | ||
951 | /* | 951 | /* |
952 | * Mount flags | 952 | * Mount flags set via mount options or defaults |
953 | */ | 953 | */ |
954 | #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ | 954 | #define EXT4_MOUNT_GRPID 0x00004 /* Create files with directory's group */ |
955 | #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ | 955 | #define EXT4_MOUNT_DEBUG 0x00008 /* Some debugging messages */ |
@@ -981,8 +981,16 @@ struct ext4_inode_info { | |||
981 | #define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */ | 981 | #define EXT4_MOUNT_DISCARD 0x40000000 /* Issue DISCARD requests */ |
982 | #define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */ | 982 | #define EXT4_MOUNT_INIT_INODE_TABLE 0x80000000 /* Initialize uninitialized itables */ |
983 | 983 | ||
984 | /* | ||
985 | * Mount flags set either automatically (could not be set by mount option) | ||
986 | * based on per file system feature or property or in special cases such as | ||
987 | * distinguishing between explicit mount option definition and default. | ||
988 | */ | ||
984 | #define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly | 989 | #define EXT4_MOUNT2_EXPLICIT_DELALLOC 0x00000001 /* User explicitly |
985 | specified delalloc */ | 990 | specified delalloc */ |
991 | #define EXT4_MOUNT2_STD_GROUP_SIZE 0x00000002 /* We have standard group | ||
992 | size of blocksize * 8 | ||
993 | blocks */ | ||
986 | 994 | ||
987 | #define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \ | 995 | #define clear_opt(sb, opt) EXT4_SB(sb)->s_mount_opt &= \ |
988 | ~EXT4_MOUNT_##opt | 996 | ~EXT4_MOUNT_##opt |
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index febbe0e18024..525beb6e3e1e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
@@ -3529,6 +3529,10 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) | |||
3529 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); | 3529 | sbi->s_addr_per_block_bits = ilog2(EXT4_ADDR_PER_BLOCK(sb)); |
3530 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); | 3530 | sbi->s_desc_per_block_bits = ilog2(EXT4_DESC_PER_BLOCK(sb)); |
3531 | 3531 | ||
3532 | /* Do we have standard group size of blocksize * 8 blocks ? */ | ||
3533 | if (sbi->s_blocks_per_group == blocksize << 3) | ||
3534 | set_opt2(sb, STD_GROUP_SIZE); | ||
3535 | |||
3532 | for (i = 0; i < 4; i++) | 3536 | for (i = 0; i < 4; i++) |
3533 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); | 3537 | sbi->s_hash_seed[i] = le32_to_cpu(es->s_hash_seed[i]); |
3534 | sbi->s_def_hash_version = es->s_def_hash_version; | 3538 | sbi->s_def_hash_version = es->s_def_hash_version; |