2007-11-04 22:09:18

by OGAWA Hirofumi

[permalink] [raw]
Subject: [PATCH 2/2] fat: optimize fat_count_free_clusters()

On large partition, scanning the free clusters is very slow if users
doesn't use "usefree" option.

For optimizing it, this patch uses sb_breadahead() to read of FAT
sectors. On some user's 15GB partition, this patch improved it very
much (1min => 600ms).

The following is the result of 2GB partition on my machine.

without patch:
root@devron (/)# time df -h > /dev/null

real 0m1.202s
user 0m0.000s
sys 0m0.440s

with patch:
root@devron (/)# time df -h > /dev/null

real 0m0.378s
user 0m0.012s
sys 0m0.168s

Signed-off-by: OGAWA Hirofumi <[email protected]>
---

fs/fat/fatent.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)

diff -puN fs/fat/fatent.c~fat_optimize-count-freeclus fs/fat/fatent.c
--- linux-2.6/fs/fat/fatent.c~fat_optimize-count-freeclus 2007-11-05 06:01:10.000000000 +0900
+++ linux-2.6-hirofumi/fs/fat/fatent.c 2007-11-05 06:01:10.000000000 +0900
@@ -590,21 +590,49 @@ error:

EXPORT_SYMBOL_GPL(fat_free_clusters);

+/* 128kb is the whole sectors for FAT12 and FAT16 */
+#define FAT_READA_SIZE (128 * 1024)
+
+static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
+ unsigned long reada_blocks)
+{
+ struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
+ sector_t blocknr;
+ int i, offset;
+
+ ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
+
+ for (i = 0; i < reada_blocks; i++)
+ sb_breadahead(sb, blocknr + i);
+}
+
int fat_count_free_clusters(struct super_block *sb)
{
struct msdos_sb_info *sbi = MSDOS_SB(sb);
struct fatent_operations *ops = sbi->fatent_ops;
struct fat_entry fatent;
+ unsigned long reada_blocks, reada_mask, cur_block;
int err = 0, free;

lock_fat(sbi);
if (sbi->free_clusters != -1)
goto out;

+ reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits;
+ reada_mask = reada_blocks - 1;
+ cur_block = 0;
+
free = 0;
fatent_init(&fatent);
fatent_set_entry(&fatent, FAT_START_ENT);
while (fatent.entry < sbi->max_cluster) {
+ /* readahead of fat blocks */
+ if ((cur_block & reada_mask) == 0) {
+ unsigned long rest = sbi->fat_length - cur_block;
+ fat_ent_reada(sb, &fatent, min(reada_blocks, rest));
+ }
+ cur_block++;
+
err = fat_ent_read_block(sb, &fatent);
if (err)
goto out;
_

--
OGAWA Hirofumi <[email protected]>


2007-11-06 00:50:09

by Andrew Morton

[permalink] [raw]
Subject: Re: [PATCH 2/2] fat: optimize fat_count_free_clusters()

On Mon, 05 Nov 2007 07:09:00 +0900
OGAWA Hirofumi <[email protected]> wrote:

> On large partition, scanning the free clusters is very slow if users
> doesn't use "usefree" option.
>
> For optimizing it, this patch uses sb_breadahead() to read of FAT
> sectors. On some user's 15GB partition, this patch improved it very
> much (1min => 600ms).
>
> The following is the result of 2GB partition on my machine.
>
> without patch:
> root@devron (/)# time df -h > /dev/null
>
> real 0m1.202s
> user 0m0.000s
> sys 0m0.440s
>
> with patch:
> root@devron (/)# time df -h > /dev/null
>
> real 0m0.378s
> user 0m0.012s
> sys 0m0.168s
>

Can't complain about that ;)

> ---
>
> fs/fat/fatent.c | 28 ++++++++++++++++++++++++++++
> 1 file changed, 28 insertions(+)
>
> diff -puN fs/fat/fatent.c~fat_optimize-count-freeclus fs/fat/fatent.c
> --- linux-2.6/fs/fat/fatent.c~fat_optimize-count-freeclus 2007-11-05 06:01:10.000000000 +0900
> +++ linux-2.6-hirofumi/fs/fat/fatent.c 2007-11-05 06:01:10.000000000 +0900
> @@ -590,21 +590,49 @@ error:
>
> EXPORT_SYMBOL_GPL(fat_free_clusters);
>
> +/* 128kb is the whole sectors for FAT12 and FAT16 */
> +#define FAT_READA_SIZE (128 * 1024)
> +
> +static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
> + unsigned long reada_blocks)
> +{
> + struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
> + sector_t blocknr;
> + int i, offset;
> +
> + ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
> +
> + for (i = 0; i < reada_blocks; i++)
> + sb_breadahead(sb, blocknr + i);
> +}

You might find that it's simpler and faster to call
page_cache_sync_readahead() against sb->s_bdev->bd_inode->i_mapping.

Or maybe not - that requires a struct file_ra_state. We _used_ to have a
nice simple read-some-stuff-into-pagecache function which didn't need an
ra_state but that seems to have disappeared in the various recent readahead
churn. Oh well.

2007-11-06 02:07:29

by OGAWA Hirofumi

[permalink] [raw]
Subject: Re: [PATCH 2/2] fat: optimize fat_count_free_clusters()

Andrew Morton <[email protected]> writes:

>> +/* 128kb is the whole sectors for FAT12 and FAT16 */
>> +#define FAT_READA_SIZE (128 * 1024)
>> +
>> +static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent,
>> + unsigned long reada_blocks)
>> +{
>> + struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops;
>> + sector_t blocknr;
>> + int i, offset;
>> +
>> + ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr);
>> +
>> + for (i = 0; i < reada_blocks; i++)
>> + sb_breadahead(sb, blocknr + i);
>> +}
>
> You might find that it's simpler and faster to call
> page_cache_sync_readahead() against sb->s_bdev->bd_inode->i_mapping.
>
> Or maybe not - that requires a struct file_ra_state. We _used_ to have a
> nice simple read-some-stuff-into-pagecache function which didn't need an
> ra_state but that seems to have disappeared in the various recent readahead
> churn. Oh well.

Yes. I found it, but I gave up for now by file_ra_state. Also I'd like
to use a large block to read FAT. I'll rethink this code after large
block was merged.

Thanks.
--
OGAWA Hirofumi <[email protected]>