[PATCH] FAT: Readahead FAT table to reduce the read request of FAT tabl

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>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.

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)) {
-- 
1.5.4.5



--
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


[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux