Blame SOURCES/0066-exfat-improve-performance-of-exfat_free_cluster-when.patch

Kmods SIG 9e3ffb
From f728760aa923f1dd3a4818368dbdbd2c7d63b370 Mon Sep 17 00:00:00 2001
Kmods SIG 9e3ffb
From: Hyeongseok Kim <hyeongseok@gmail.com>
Kmods SIG 9e3ffb
Date: Mon, 1 Feb 2021 10:02:46 +0900
Kmods SIG 9e3ffb
Subject: [Backport f728760aa923] exfat: improve performance of
Kmods SIG 9e3ffb
 exfat_free_cluster when using dirsync mount option
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
There are stressful update of cluster allocation bitmap when using
Kmods SIG 9e3ffb
dirsync mount option which is doing sync buffer on every cluster bit
Kmods SIG 9e3ffb
clearing. This could result in performance degradation when deleting
Kmods SIG 9e3ffb
big size file.
Kmods SIG 9e3ffb
Fix to update only when the bitmap buffer index is changed would make
Kmods SIG 9e3ffb
less disk access, improving performance especially for truncate operation.
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
Testing with Samsung 256GB sdcard, mounted with dirsync option
Kmods SIG 9e3ffb
(mount -t exfat /dev/block/mmcblk0p1 /temp/mount -o dirsync)
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
Remove 4GB file, blktrace result.
Kmods SIG 9e3ffb
[Before] : 39 secs.
Kmods SIG 9e3ffb
Total (blktrace):
Kmods SIG 9e3ffb
 Reads Queued:      0,        0KiB   Writes Queued:      32775,    16387KiB
Kmods SIG 9e3ffb
 Read Dispatches:   0,        0KiB   Write Dispatches:   32775,    16387KiB
Kmods SIG 9e3ffb
 Reads Requeued:    0                Writes Requeued:        0
Kmods SIG 9e3ffb
 Reads Completed:   0,        0KiB   Writes Completed:   32775,    16387KiB
Kmods SIG 9e3ffb
 Read Merges:       0,        0KiB   Write Merges:           0,        0KiB
Kmods SIG 9e3ffb
 IO unplugs:        2                Timer unplugs:          0
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
[After] : 1 sec.
Kmods SIG 9e3ffb
Total (blktrace):
Kmods SIG 9e3ffb
 Reads Queued:      0,        0KiB   Writes Queued:         13,        6KiB
Kmods SIG 9e3ffb
 Read Dispatches:   0,        0KiB   Write Dispatches:      13,        6KiB
Kmods SIG 9e3ffb
 Reads Requeued:    0                Writes Requeued:        0
Kmods SIG 9e3ffb
 Reads Completed:   0,        0KiB   Writes Completed:      13,        6KiB
Kmods SIG 9e3ffb
 Read Merges:       0,        0KiB   Write Merges:           0,        0KiB
Kmods SIG 9e3ffb
 IO unplugs:        1                Timer unplugs:          0
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
Kmods SIG 9e3ffb
Acked-by: Sungjong Seo <sj1557.seo@samsung.com>
Kmods SIG 9e3ffb
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Kmods SIG 9e3ffb
---
Kmods SIG 9e3ffb
 src/balloc.c   |  4 ++--
Kmods SIG 9e3ffb
 src/exfat_fs.h |  2 +-
Kmods SIG 9e3ffb
 src/fatent.c   | 43 +++++++++++++++++++++++++++++++++++++------
Kmods SIG 9e3ffb
 3 files changed, 40 insertions(+), 9 deletions(-)
Kmods SIG 9e3ffb
Kmods SIG 9e3ffb
diff --git a/src/balloc.c b/src/balloc.c
Kmods SIG 9e3ffb
index a987919686c0d4d339ce71d11887d9510280df77..761c79c3a4ba262870686608f3619c98312f65cb 100644
Kmods SIG 9e3ffb
--- a/src/balloc.c
Kmods SIG 9e3ffb
+++ b/src/balloc.c
Kmods SIG 9e3ffb
@@ -166,7 +166,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu)
Kmods SIG 9e3ffb
  * If the value of "clu" is 0, it means cluster 2 which is the first cluster of
Kmods SIG 9e3ffb
  * the cluster heap.
Kmods SIG 9e3ffb
  */
Kmods SIG 9e3ffb
-void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
Kmods SIG 9e3ffb
+void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync)
Kmods SIG 9e3ffb
 {
Kmods SIG 9e3ffb
 	int i, b;
Kmods SIG 9e3ffb
 	unsigned int ent_idx;
Kmods SIG 9e3ffb
@@ -180,7 +180,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
Kmods SIG 9e3ffb
 	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
 	clear_bit_le(b, sbi->vol_amap[i]->b_data);
Kmods SIG 9e3ffb
-	exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
Kmods SIG 9e3ffb
+	exfat_update_bh(sbi->vol_amap[i], sync);
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
 	if (opts->discard) {
Kmods SIG 9e3ffb
 		int ret_discard;
Kmods SIG 9e3ffb
diff --git a/src/exfat_fs.h b/src/exfat_fs.h
Kmods SIG 9e3ffb
index b8f0e829ecbd26c14788899de066e533b6dbaf1e..764bc645241ed8e401d34d73b28d347d29ceed56 100644
Kmods SIG 9e3ffb
--- a/src/exfat_fs.h
Kmods SIG 9e3ffb
+++ b/src/exfat_fs.h
Kmods SIG 9e3ffb
@@ -408,7 +408,7 @@ int exfat_count_num_clusters(struct super_block *sb,
Kmods SIG 9e3ffb
 int exfat_load_bitmap(struct super_block *sb);
Kmods SIG 9e3ffb
 void exfat_free_bitmap(struct exfat_sb_info *sbi);
Kmods SIG 9e3ffb
 int exfat_set_bitmap(struct inode *inode, unsigned int clu);
Kmods SIG 9e3ffb
-void exfat_clear_bitmap(struct inode *inode, unsigned int clu);
Kmods SIG 9e3ffb
+void exfat_clear_bitmap(struct inode *inode, unsigned int clu, bool sync);
Kmods SIG 9e3ffb
 unsigned int exfat_find_free_bitmap(struct super_block *sb, unsigned int clu);
Kmods SIG 9e3ffb
 int exfat_count_used_clusters(struct super_block *sb, unsigned int *ret_count);
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
diff --git a/src/fatent.c b/src/fatent.c
Kmods SIG 9e3ffb
index c3c9afee7418f1871a65757d79f8d4a13fe650c2..7b2e8af17193bfffe00b4e0b8b88cccb34b1970a 100644
Kmods SIG 9e3ffb
--- a/src/fatent.c
Kmods SIG 9e3ffb
+++ b/src/fatent.c
Kmods SIG 9e3ffb
@@ -157,6 +157,7 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
Kmods SIG 9e3ffb
 	unsigned int clu;
Kmods SIG 9e3ffb
 	struct super_block *sb = inode->i_sb;
Kmods SIG 9e3ffb
 	struct exfat_sb_info *sbi = EXFAT_SB(sb);
Kmods SIG 9e3ffb
+	int cur_cmap_i, next_cmap_i;
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
 	/* invalid cluster number */
Kmods SIG 9e3ffb
 	if (p_chain->dir == EXFAT_FREE_CLUSTER ||
Kmods SIG 9e3ffb
@@ -176,21 +177,51 @@ int exfat_free_cluster(struct inode *inode, struct exfat_chain *p_chain)
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
 	clu = p_chain->dir;
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
+	cur_cmap_i = next_cmap_i =
Kmods SIG 9e3ffb
+		BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu));
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
 	if (p_chain->flags == ALLOC_NO_FAT_CHAIN) {
Kmods SIG 9e3ffb
+		unsigned int last_cluster = p_chain->dir + p_chain->size - 1;
Kmods SIG 9e3ffb
 		do {
Kmods SIG 9e3ffb
-			exfat_clear_bitmap(inode, clu);
Kmods SIG 9e3ffb
-			clu++;
Kmods SIG 9e3ffb
+			bool sync = false;
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
+			if (clu < last_cluster)
Kmods SIG 9e3ffb
+				next_cmap_i =
Kmods SIG 9e3ffb
+				  BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(clu+1));
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
+			/* flush bitmap only if index would be changed or for last cluster */
Kmods SIG 9e3ffb
+			if (clu == last_cluster || cur_cmap_i != next_cmap_i) {
Kmods SIG 9e3ffb
+				sync = true;
Kmods SIG 9e3ffb
+				cur_cmap_i = next_cmap_i;
Kmods SIG 9e3ffb
+			}
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
+			exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
Kmods SIG 9e3ffb
+			clu++;
Kmods SIG 9e3ffb
 			num_clusters++;
Kmods SIG 9e3ffb
 		} while (num_clusters < p_chain->size);
Kmods SIG 9e3ffb
 	} else {
Kmods SIG 9e3ffb
 		do {
Kmods SIG 9e3ffb
-			exfat_clear_bitmap(inode, clu);
Kmods SIG 9e3ffb
-
Kmods SIG 9e3ffb
-			if (exfat_get_next_cluster(sb, &clu))
Kmods SIG 9e3ffb
-				goto dec_used_clus;
Kmods SIG 9e3ffb
+			bool sync = false;
Kmods SIG 9e3ffb
+			unsigned int n_clu = clu;
Kmods SIG 9e3ffb
+			int err = exfat_get_next_cluster(sb, &n_clu);
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
+			if (err || n_clu == EXFAT_EOF_CLUSTER)
Kmods SIG 9e3ffb
+				sync = true;
Kmods SIG 9e3ffb
+			else
Kmods SIG 9e3ffb
+				next_cmap_i =
Kmods SIG 9e3ffb
+				  BITMAP_OFFSET_SECTOR_INDEX(sb, CLUSTER_TO_BITMAP_ENT(n_clu));
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
+			if (cur_cmap_i != next_cmap_i) {
Kmods SIG 9e3ffb
+				sync = true;
Kmods SIG 9e3ffb
+				cur_cmap_i = next_cmap_i;
Kmods SIG 9e3ffb
+			}
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
+			exfat_clear_bitmap(inode, clu, (sync && IS_DIRSYNC(inode)));
Kmods SIG 9e3ffb
+			clu = n_clu;
Kmods SIG 9e3ffb
 			num_clusters++;
Kmods SIG 9e3ffb
+
Kmods SIG 9e3ffb
+			if (err)
Kmods SIG 9e3ffb
+				goto dec_used_clus;
Kmods SIG 9e3ffb
 		} while (clu != EXFAT_EOF_CLUSTER);
Kmods SIG 9e3ffb
 	}
Kmods SIG 9e3ffb
 
Kmods SIG 9e3ffb
-- 
Kmods SIG 9e3ffb
2.31.1
Kmods SIG 9e3ffb