aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKarsten Wiese <annabellesgarden@yahoo.de>2005-09-06 18:17:12 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 19:57:26 -0400
commitf3ef6f63e5c575c136b39bb423a6e9a002932da7 (patch)
treeed58cfc7e6e31bd08ec7129d310c41575d0453df
parent378bac820be6a0ec95df8151524de73ad2b2d2ac (diff)
[PATCH] Speedup FAT filesystem directory reads
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> This speeds up directory reads for large FAT partitions, if the buffercache has to be filled from the drive. Following values were taken from: $ time find path_to_freshly_mounted_fat > /dev/null on an otherwise idle system. FAT with 16KB Clusters on IDE attached drive: Factor 2 FAT with 32KB Clusters on USB2 attached drive: Factor 10 (!) Its less than 1/10 slower, if the buffercache is uptodate. The patch introduces the new function fat_dir_readahead(). fat_dir_readahead() calls sb_breadahead() to readahead a whole cluster, if the requested sector is the first one in a cluster. It is usefull to do this, because on FAT directories occupy whole clusters, with the exception of FAT12/FAT16 root dirs. Readahead is only done, if the cluster's first sector is not uptodate to avoid overhead, when the buffer cache is already uptodate. Note that under memory pressure, the maximal byte count wasted (read: has to be red from disk twice) is 1 cluster's size. Thats 64KB. fat_dir_readahead() is called from fat__get_entry(). There is also an unrelated cleanup at one spot: if (bh) brelse(bh); is replaced with: brelse(bh); brelse() can handle NULL pointer arguments by itself. Signed-off-by: Karsten Wiese <annabellesgarden@yahoo.de> Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/fat/dir.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index e5ae1b720dde..895049b2ac9c 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -30,6 +30,29 @@ static inline loff_t fat_make_i_pos(struct super_block *sb,
30 | (de - (struct msdos_dir_entry *)bh->b_data); 30 | (de - (struct msdos_dir_entry *)bh->b_data);
31} 31}
32 32
33static inline void fat_dir_readahead(struct inode *dir, sector_t iblock,
34 sector_t phys)
35{
36 struct super_block *sb = dir->i_sb;
37 struct msdos_sb_info *sbi = MSDOS_SB(sb);
38 struct buffer_head *bh;
39 int sec;
40
41 /* This is not a first sector of cluster, or sec_per_clus == 1 */
42 if ((iblock & (sbi->sec_per_clus - 1)) || sbi->sec_per_clus == 1)
43 return;
44 /* root dir of FAT12/FAT16 */
45 if ((sbi->fat_bits != 32) && (dir->i_ino == MSDOS_ROOT_INO))
46 return;
47
48 bh = sb_getblk(sb, phys);
49 if (bh && !buffer_uptodate(bh)) {
50 for (sec = 0; sec < sbi->sec_per_clus; sec++)
51 sb_breadahead(sb, phys + sec);
52 }
53 brelse(bh);
54}
55
33/* Returns the inode number of the directory entry at offset pos. If bh is 56/* Returns the inode number of the directory entry at offset pos. If bh is
34 non-NULL, it is brelse'd before. Pos is incremented. The buffer header is 57 non-NULL, it is brelse'd before. Pos is incremented. The buffer header is
35 returned in bh. 58 returned in bh.
@@ -58,6 +81,8 @@ next:
58 if (err || !phys) 81 if (err || !phys)
59 return -1; /* beyond EOF or error */ 82 return -1; /* beyond EOF or error */
60 83
84 fat_dir_readahead(dir, iblock, phys);
85
61 *bh = sb_bread(sb, phys); 86 *bh = sb_bread(sb, phys);
62 if (*bh == NULL) { 87 if (*bh == NULL) {
63 printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", 88 printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n",
@@ -635,8 +660,7 @@ RecEnd:
635EODir: 660EODir:
636 filp->f_pos = cpos; 661 filp->f_pos = cpos;
637FillFailed: 662FillFailed:
638 if (bh) 663 brelse(bh);
639 brelse(bh);
640 if (unicode) 664 if (unicode)
641 free_page((unsigned long)unicode); 665 free_page((unsigned long)unicode);
642out: 666out: