Skip to content

Commit

Permalink
fat: optimize fat_count_free_clusters()
Browse files Browse the repository at this point in the history
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]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
OGAWAHirofumi authored and Linus Torvalds committed Jan 9, 2008
1 parent d52df2e commit 9f966be
Showing 1 changed file with 28 additions and 0 deletions.
28 changes: 28 additions & 0 deletions fs/fat/fatent.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,21 +590,49 @@ int fat_free_clusters(struct inode *inode, int cluster)

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;
Expand Down

0 comments on commit 9f966be

Please sign in to comment.