FAT: Readahead FAT table to reduce the read request of FAT tabl
Subsystems (2)
PATCH 1/1 FAT: Readahead FAT table to reduce the read request of FAT tabl
Quoted 1 line
From
badc27e6b5f732191fb3b7e964f68da030144c76Mon Sep 17 00:00:00 2001
From: Zhao Yakui <[email protected]>
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.
---
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(-)
fs/fat/fat.h +1 -0
@@ -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 ];
fs/fat/fatent.c +26 -0
@@ -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 ]) {
fs/fat/inode.c +4 -0
@@ -34,6 +34,8 @@#define CONFIG_FAT_DEFAULT_IOCHARSET ""#endif + +#define FAT_MAX_READAHEAD 32768static 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 )) {
Signature · 1 line
1.5.4.5
Quoted 10 lines · ykzhao
Quoted 1 line
From
badc27e6b5f732191fb3b7e964f68da030144c76Mon Sep 17 00:00:00 2001From: Zhao Yakui <[email protected]>
Date: Fri, 19 Nov 2010 10:29:33 +0800
Subject: [PATCH] FAT: Readahead FAT table to reduce the read request of FAT tableOn 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
Quoted 111 lines
Signed-off-by Zhao Yakui <[email protected]>---
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(-)fs/fat/fat.h +1
-0@@ -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 ];fs/fat/fatent.c +26
-0@@ -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 ]) {fs/fat/inode.c +4
-0@@ -34,6 +34,8 @@#define CONFIG_FAT_DEFAULT_IOCHARSET ""#endif + +#define FAT_MAX_READAHEAD 32768static 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 )) {
Quoted 5 lines · ykzhao
Quoted 1 line
From
badc27e6b5f732191fb3b7e964f68da030144c76Mon Sep 17 00:00:00 2001From: Zhao Yakui <[email protected]>
Date: Fri, 19 Nov 2010 10:29:33 +0800
Subject: [PATCH] FAT: Readahead FAT table to reduce the read request of FAT table
Quoted 7 lines
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 <[email protected]>
Hi, Hirofumi
Does this patch make sense to you?
thanks
Quoted 109 lines
---
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(-)fs/fat/fat.h +1
-0@@ -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 ];fs/fat/fatent.c +26
-0@@ -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 ]) {fs/fat/inode.c +4
-0@@ -34,6 +34,8 @@#define CONFIG_FAT_DEFAULT_IOCHARSET ""#endif + +#define FAT_MAX_READAHEAD 32768static 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 )) {
Quoted 19 lines · On Thu, 25 Nov 2010 16:46:37 +0800 ykzhao <[email protected]> wrote:
Quoted 1 line
From
badc27e6b5f732191fb3b7e964f68da030144c76Mon Sep 17 00:00:00 2001From: Zhao Yakui <[email protected]>
Date: Fri, 19 Nov 2010 10:29:33 +0800
Subject: [PATCH] FAT: Readahead FAT table to reduce the read request of FAT tableOn 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 <[email protected]>---
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).
Quoted 4 lines
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).
Seems reasonable.
Quoted 17 lines
fs/fat/fatent.c +9
-0@@ -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
fs/fat/fatent.c static void fat32_ent_set_ptr(struct fat_entry *fatent, int offset) · line 88
Quoted 10 lines
fs/fat/fatent.c +10
-0+* 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); +}
A few things.
a) I'd like to be really really convinced that there's no way in which this function can wander off the end of the device. Or that the called functions handle this situation gracefully.
b) Lots of (old) filesystems probably do block-level readahead like this. We really should have a generic vfs-layer library function, rather than open-coding it all the time.
c) sb_breadahead() is a truly ancient function. It would be nice to use the more modern (and probably more efficient) force_page_cache_readahead(). It should be OK to pass filp==0.