diff options
| author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2008-01-08 18:32:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-01-08 19:10:35 -0500 |
| commit | 9f966be8996f2829406324c68e4c67c2d64d864b (patch) | |
| tree | 40b2e1f12834498f1e7d8240fe7f6f3dbaf0dce2 | |
| parent | d52df2e2ea2d881b1439bbdec7f67c27e0f47941 (diff) | |
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 <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | fs/fat/fatent.c | 28 |
1 files changed, 28 insertions, 0 deletions
diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c index 2c1b73fb82ae..5fb366992b73 100644 --- a/fs/fat/fatent.c +++ b/fs/fat/fatent.c | |||
| @@ -590,21 +590,49 @@ error: | |||
| 590 | 590 | ||
| 591 | EXPORT_SYMBOL_GPL(fat_free_clusters); | 591 | EXPORT_SYMBOL_GPL(fat_free_clusters); |
| 592 | 592 | ||
| 593 | /* 128kb is the whole sectors for FAT12 and FAT16 */ | ||
| 594 | #define FAT_READA_SIZE (128 * 1024) | ||
| 595 | |||
| 596 | static void fat_ent_reada(struct super_block *sb, struct fat_entry *fatent, | ||
| 597 | unsigned long reada_blocks) | ||
| 598 | { | ||
| 599 | struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; | ||
| 600 | sector_t blocknr; | ||
| 601 | int i, offset; | ||
| 602 | |||
| 603 | ops->ent_blocknr(sb, fatent->entry, &offset, &blocknr); | ||
| 604 | |||
| 605 | for (i = 0; i < reada_blocks; i++) | ||
| 606 | sb_breadahead(sb, blocknr + i); | ||
| 607 | } | ||
| 608 | |||
| 593 | int fat_count_free_clusters(struct super_block *sb) | 609 | int fat_count_free_clusters(struct super_block *sb) |
| 594 | { | 610 | { |
| 595 | struct msdos_sb_info *sbi = MSDOS_SB(sb); | 611 | struct msdos_sb_info *sbi = MSDOS_SB(sb); |
| 596 | struct fatent_operations *ops = sbi->fatent_ops; | 612 | struct fatent_operations *ops = sbi->fatent_ops; |
| 597 | struct fat_entry fatent; | 613 | struct fat_entry fatent; |
| 614 | unsigned long reada_blocks, reada_mask, cur_block; | ||
| 598 | int err = 0, free; | 615 | int err = 0, free; |
| 599 | 616 | ||
| 600 | lock_fat(sbi); | 617 | lock_fat(sbi); |
| 601 | if (sbi->free_clusters != -1) | 618 | if (sbi->free_clusters != -1) |
| 602 | goto out; | 619 | goto out; |
| 603 | 620 | ||
| 621 | reada_blocks = FAT_READA_SIZE >> sb->s_blocksize_bits; | ||
| 622 | reada_mask = reada_blocks - 1; | ||
| 623 | cur_block = 0; | ||
| 624 | |||
| 604 | free = 0; | 625 | free = 0; |
| 605 | fatent_init(&fatent); | 626 | fatent_init(&fatent); |
| 606 | fatent_set_entry(&fatent, FAT_START_ENT); | 627 | fatent_set_entry(&fatent, FAT_START_ENT); |
| 607 | while (fatent.entry < sbi->max_cluster) { | 628 | while (fatent.entry < sbi->max_cluster) { |
| 629 | /* readahead of fat blocks */ | ||
| 630 | if ((cur_block & reada_mask) == 0) { | ||
| 631 | unsigned long rest = sbi->fat_length - cur_block; | ||
| 632 | fat_ent_reada(sb, &fatent, min(reada_blocks, rest)); | ||
| 633 | } | ||
| 634 | cur_block++; | ||
| 635 | |||
| 608 | err = fat_ent_read_block(sb, &fatent); | 636 | err = fat_ent_read_block(sb, &fatent); |
| 609 | if (err) | 637 | if (err) |
| 610 | goto out; | 638 | goto out; |
