Commit 5e70030d authored by Badari Pulavarty's avatar Badari Pulavarty Committed by Linus Torvalds

ext4: statfs speed up

This is a patch that speeds up statfs.  It is very simple - the "overhead"
calculation, which takes a huge amount of time for large filesystems, never
changes unless the size of the filesystem itself changes.  That means we can
store it in memory and only recalculate if the filesystem has been resized
(almost never).

It also fixes a minor problem that we never update the on-disk superblock free
blocks/inodes counts until the filesystem is unmounted.  While not fatal, we
may as well update that on disk when we have the information, and it makes
things like debugfs and dumpe2fs report a bit more accurate info.
Signed-off-by: default avatarBadari Pulavarty <pbadari@us.ibm.com>
Signed-off-by: default avatarAndreas Dilger <adilger@clusterfs.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent a71ce8c6
...@@ -2500,19 +2500,19 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) ...@@ -2500,19 +2500,19 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
struct ext4_sb_info *sbi = EXT4_SB(sb); struct ext4_sb_info *sbi = EXT4_SB(sb);
struct ext4_super_block *es = sbi->s_es; struct ext4_super_block *es = sbi->s_es;
ext4_fsblk_t overhead;
int i;
u64 fsid; u64 fsid;
if (test_opt (sb, MINIX_DF)) if (test_opt(sb, MINIX_DF)) {
overhead = 0; sbi->s_overhead_last = 0;
else { } else if (sbi->s_blocks_last != le32_to_cpu(es->s_blocks_count)) {
unsigned long ngroups; unsigned long ngroups = sbi->s_groups_count, i;
ngroups = EXT4_SB(sb)->s_groups_count; ext4_fsblk_t overhead = 0;
smp_rmb(); smp_rmb();
/* /*
* Compute the overhead (FS structures) * Compute the overhead (FS structures). This is constant
* for a given filesystem unless the number of block groups
* changes so we cache the previous value until it does.
*/ */
/* /*
...@@ -2536,18 +2536,23 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf) ...@@ -2536,18 +2536,23 @@ static int ext4_statfs (struct dentry * dentry, struct kstatfs * buf)
* Every block group has an inode bitmap, a block * Every block group has an inode bitmap, a block
* bitmap, and an inode table. * bitmap, and an inode table.
*/ */
overhead += (ngroups * (2 + EXT4_SB(sb)->s_itb_per_group)); overhead += ngroups * (2 + sbi->s_itb_per_group);
sbi->s_overhead_last = overhead;
smp_wmb();
sbi->s_blocks_last = le32_to_cpu(es->s_blocks_count);
} }
buf->f_type = EXT4_SUPER_MAGIC; buf->f_type = EXT4_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_blocks = ext4_blocks_count(es) - overhead; buf->f_blocks = ext4_blocks_count(es) - sbi->s_overhead_last;
buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter); buf->f_bfree = percpu_counter_sum(&sbi->s_freeblocks_counter);
es->s_free_blocks_count = cpu_to_le32(buf->f_bfree);
buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es); buf->f_bavail = buf->f_bfree - ext4_r_blocks_count(es);
if (buf->f_bfree < ext4_r_blocks_count(es)) if (buf->f_bfree < ext4_r_blocks_count(es))
buf->f_bavail = 0; buf->f_bavail = 0;
buf->f_files = le32_to_cpu(es->s_inodes_count); buf->f_files = le32_to_cpu(es->s_inodes_count);
buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter); buf->f_ffree = percpu_counter_sum(&sbi->s_freeinodes_counter);
es->s_free_inodes_count = cpu_to_le32(buf->f_ffree);
buf->f_namelen = EXT4_NAME_LEN; buf->f_namelen = EXT4_NAME_LEN;
fsid = le64_to_cpup((void *)es->s_uuid) ^ fsid = le64_to_cpup((void *)es->s_uuid) ^
le64_to_cpup((void *)es->s_uuid + sizeof(u64)); le64_to_cpup((void *)es->s_uuid + sizeof(u64));
......
...@@ -39,6 +39,8 @@ struct ext4_sb_info { ...@@ -39,6 +39,8 @@ struct ext4_sb_info {
unsigned long s_gdb_count; /* Number of group descriptor blocks */ unsigned long s_gdb_count; /* Number of group descriptor blocks */
unsigned long s_desc_per_block; /* Number of group descriptors per block */ unsigned long s_desc_per_block; /* Number of group descriptors per block */
unsigned long s_groups_count; /* Number of groups in the fs */ unsigned long s_groups_count; /* Number of groups in the fs */
unsigned long s_overhead_last; /* Last calculated overhead */
unsigned long s_blocks_last; /* Last seen block count */
struct buffer_head * s_sbh; /* Buffer containing the super block */ struct buffer_head * s_sbh; /* Buffer containing the super block */
struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */ struct ext4_super_block * s_es; /* Pointer to the super block in the buffer */
struct buffer_head ** s_group_desc; struct buffer_head ** s_group_desc;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment