On Thu, 2010-11-25 at 16:46 +0800, ykzhao wrote: > >From badc27e6b5f732191fb3b7e964f68da030144c76 Mon Sep 17 00:00:00 2001 > From: Zhao Yakui <yakui.zhao@xxxxxxxxx> > Date: Fri, 19 Nov 2010 10:29:33 +0800 > Subject: [PATCH] FAT: Readahead FAT table to reduce the read request of FAT table > > On FAT filesystem the FAT table will be accessed very frequently when > reading/writing the file. Now it reads only block sector from FAT table every > time and it will have to wait for the completion of read-access. In fact > as the FAT table is located sequentially on the disk, maybe we can readahead > the following sectors to reduce the read access of FAT table. Hi, Hirofumi Does this patch make sense to you? thanks. Yakui > > Signed-off-by: Zhao Yakui <yakui.zhao@xxxxxxxxx> > --- > The following is the test result on SD card/U-disk. > a. Read/Write a large file by using direct mode on SD card > dd if=sda.bin of=sda.bin2 bs=64k iflag=direct > The average copy time can be reduced from 470 second to 452 seconds(The file > of sda.bin is about 1.8G). > > a. Read/Write a large file by using direct mode on U-disk > dd if=sda.bin of=sda.bin2 bs=64k iflag=direct > The average copy time can be reduced from about 880 to 855 seconds.(The file > of sda.bin is about 1.8G). > > fs/fat/fat.h | 1 + > fs/fat/fatent.c | 26 ++++++++++++++++++++++++++ > fs/fat/inode.c | 4 ++++ > 3 files changed, 31 insertions(+), 0 deletions(-) > > diff --git a/fs/fat/fat.h b/fs/fat/fat.h > index d75a77f..caf5449 100644 > --- a/fs/fat/fat.h > +++ b/fs/fat/fat.h > @@ -84,6 +84,7 @@ struct msdos_sb_info { > struct inode *fat_inode; > > struct ratelimit_state ratelimit; > + int fat_readahead_cnt; /* block number for readahead FAT table every time */ > > spinlock_t inode_hash_lock; > struct hlist_head inode_hashtable[FAT_HASH_SIZE]; > diff --git a/fs/fat/fatent.c b/fs/fat/fatent.c > index b47d2c9..1dfd73f 100644 > --- a/fs/fat/fatent.c > +++ b/fs/fat/fatent.c > @@ -67,6 +67,26 @@ static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset) > fatent->u.ent32_p = (__le32 *)(fatent->bhs[0]->b_data + offset); > } > > +static void fat_table_readahead(struct super_block *sb, sector_t iphys) > +{ > + struct msdos_sb_info *sbi = MSDOS_SB(sb); > + struct buffer_head *bh; > + int sec, sec_count; > + > + sec_count = sbi->fat_readahead_cnt; > + /* > + * It will check whether the current block is already obtained from the > + * disk. If not, we will try to readahead more sectors when > + * reading the FAT table > + */ > + bh = sb_find_get_block(sb, iphys); > + if (bh == NULL || !buffer_uptodate(bh)) { > + for (sec = 0; sec < sec_count; sec++) > + sb_breadahead(sb, iphys + sec); > + } > + brelse(bh); > +} > + > static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, > int offset, sector_t blocknr) > { > @@ -75,6 +95,7 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, > WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); > fatent->fat_inode = MSDOS_SB(sb)->fat_inode; > > + fat_table_readahead(sb, blocknr); > bhs[0] = sb_bread(sb, blocknr); > if (!bhs[0]) > goto err; > @@ -84,6 +105,7 @@ static int fat12_ent_bread(struct super_block *sb, struct fat_entry *fatent, > else { > /* This entry is block boundary, it needs the next block */ > blocknr++; > + fat_table_readahead(sb, blocknr); > bhs[1] = sb_bread(sb, blocknr); > if (!bhs[1]) > goto err_brelse; > @@ -105,6 +127,10 @@ static int fat_ent_bread(struct super_block *sb, struct fat_entry *fatent, > struct fatent_operations *ops = MSDOS_SB(sb)->fatent_ops; > > WARN_ON(blocknr < MSDOS_SB(sb)->fat_start); > + > + /* readahead the content of FAT table */ > + fat_table_readahead(sb, blocknr); > + > fatent->fat_inode = MSDOS_SB(sb)->fat_inode; > fatent->bhs[0] = sb_bread(sb, blocknr); > if (!fatent->bhs[0]) { > diff --git a/fs/fat/inode.c b/fs/fat/inode.c > index ad6998a..fa00b6f 100644 > --- a/fs/fat/inode.c > +++ b/fs/fat/inode.c > @@ -34,6 +34,8 @@ > #define CONFIG_FAT_DEFAULT_IOCHARSET "" > #endif > > + > +#define FAT_MAX_READAHEAD 32768 > static int fat_default_codepage = CONFIG_FAT_DEFAULT_CODEPAGE; > static char fat_default_iocharset[] = CONFIG_FAT_DEFAULT_IOCHARSET; > > @@ -1406,6 +1408,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, > sbi->dir_per_block = sb->s_blocksize / sizeof(struct msdos_dir_entry); > sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1; > > + > + sbi->fat_readahead_cnt = FAT_MAX_READAHEAD / sb->s_blocksize; > sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length; > sbi->dir_entries = get_unaligned_le16(&b->dir_entries); > if (sbi->dir_entries & (sbi->dir_per_block - 1)) { -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html