Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1d092fc3 authored by Yuezhang Mo's avatar Yuezhang Mo Committed by Namjae Jeon
Browse files

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: default avatarYuezhang Mo <Yuezhang.Mo@sony.com>
Reviewed-by: default avatarAndy Wu <Andy.Wu@sony.com>
Reviewed-by: default avatarAoyama Wataru <wataru.aoyama@sony.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Acked-by: default avatarSungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
parent 8dbffe20
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
#include <linux/slab.h>
#include <asm/unaligned.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>

#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 @@ int exfat_zeroed_cluster(struct inode *dir, unsigned int clu)
		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)