From 1d092fc3520025335ae4c7433b637e6000aa9bdd Mon Sep 17 00:00:00 2001 From: Yuezhang Mo Date: Fri, 8 Apr 2022 22:14:06 +0900 Subject: [PATCH] exfat: reduce block requests when zeroing a cluster If 'dirsync' is enabled, when zeroing a cluster, submitting sector by sector will generate many block requests, will cause the block device to not fully perform its performance. This commit makes the sectors in a cluster to be submitted in once, it will reduce the number of block requests. This will make the block device to give full play to its performance. Test create 1000 directories on SD card with: $ time (for ((i=0;i<1000;i++)); do mkdir dir${i}; done) Performance has been improved by more than 73% on imx6q-sabrelite. Cluster size Before After Improvement 64 KBytes 3m34.036s 0m56.052s 73.8% 128 KBytes 6m2.644s 1m13.354s 79.8% 256 KBytes 11m22.202s 1m39.451s 85.4% imx6q-sabrelite: - CPU: 792 MHz x4 - Memory: 1GB DDR3 - SD Card: SanDisk 8GB Class 4 Signed-off-by: Yuezhang Mo Reviewed-by: Andy Wu Reviewed-by: Aoyama Wataru Reviewed-by: Christoph Hellwig Acked-by: Sungjong Seo Signed-off-by: Namjae Jeon --- fatent.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/fatent.c b/fatent.c index ca725516972f..61fbf9f3e958 100644 --- a/fatent.c +++ b/fatent.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "exfat_raw.h" #include "exfat_fs.h" @@ -278,6 +279,46 @@ int exfat_find_last_cluster(struct super_block *sb, struct exfat_chain *p_chain, return 0; } +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) +int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) +{ + struct super_block *sb = dir->i_sb; + struct exfat_sb_info *sbi = EXFAT_SB(sb); + struct buffer_head *bh; + sector_t blknr, last_blknr; + int i; + + blknr = exfat_cluster_to_sector(sbi, clu); + last_blknr = blknr + sbi->sect_per_clus; + + if (last_blknr > sbi->num_sectors && sbi->num_sectors > 0) { + exfat_fs_error_ratelimit(sb, + "%s: out of range(sect:%llu len:%u)", + __func__, (unsigned long long)blknr, + sbi->sect_per_clus); + return -EIO; + } + + /* Zeroing the unused blocks on this cluster */ + for (i = blknr; i < last_blknr; i++) { + bh = sb_getblk(sb, i); + if (!bh) + return -ENOMEM; + + memset(bh->b_data, 0, sb->s_blocksize); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + brelse(bh); + } + + if (IS_DIRSYNC(dir)) + return sync_blockdev_range(sb->s_bdev, + EXFAT_BLK_TO_B(blknr, sb), + EXFAT_BLK_TO_B(last_blknr, sb) - 1); + + return 0; +} +#else int exfat_zeroed_cluster(struct inode *dir, unsigned int clu) { struct super_block *sb = dir->i_sb; @@ -324,6 +365,7 @@ release_bhs: bforget(bhs[i]); return err; } +#endif int exfat_alloc_cluster(struct inode *inode, unsigned int num_alloc, struct exfat_chain *p_chain, bool sync_bmap)