Blame SOURCES/0074-exfat-speed-up-iterate-lookup-by-fixing-start-point-.patch

Kmods SIG 50e2b3
From c6e2f52e3051e8d898d38840104638ca8bbcdec2 Mon Sep 17 00:00:00 2001
Kmods SIG 50e2b3
From: Hyeongseok Kim <hyeongseok@gmail.com>
Kmods SIG 50e2b3
Date: Mon, 22 Mar 2021 12:53:36 +0900
Kmods SIG 50e2b3
Subject: [Backport c6e2f52e3051] exfat: speed up iterate/lookup by fixing
Kmods SIG 50e2b3
 start point of traversing cluster chain
Kmods SIG 50e2b3
Kmods SIG 50e2b3
When directory iterate and lookup is called, there's a buggy rewinding
Kmods SIG 50e2b3
of start point for traversing cluster chain to the parent directory
Kmods SIG 50e2b3
entry's first cluster. This caused repeated cluster chain traversing
Kmods SIG 50e2b3
from the first entry of the parent directory that would show worse
Kmods SIG 50e2b3
performance if huge amounts of files exist under the parent directory.
Kmods SIG 50e2b3
Fix not to rewind, make continue from currently referenced cluster and
Kmods SIG 50e2b3
dir entry.
Kmods SIG 50e2b3
Kmods SIG 50e2b3
Tested with 50,000 files under single directory / 256GB sdcard,
Kmods SIG 50e2b3
with command "time ls -l > /dev/null",
Kmods SIG 50e2b3
Before :     0m08.69s real     0m00.27s user     0m05.91s system
Kmods SIG 50e2b3
After  :     0m07.01s real     0m00.25s user     0m04.34s system
Kmods SIG 50e2b3
Kmods SIG 50e2b3
Signed-off-by: Hyeongseok Kim <hyeongseok@gmail.com>
Kmods SIG 50e2b3
Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com>
Kmods SIG 50e2b3
Signed-off-by: Namjae Jeon <namjae.jeon@samsung.com>
Kmods SIG 50e2b3
---
Kmods SIG 50e2b3
 src/dir.c      | 19 +++++++++++++------
Kmods SIG 50e2b3
 src/exfat_fs.h |  2 +-
Kmods SIG 50e2b3
 src/namei.c    |  9 ++++++++-
Kmods SIG 50e2b3
 3 files changed, 22 insertions(+), 8 deletions(-)
Kmods SIG 50e2b3
Kmods SIG 50e2b3
diff --git a/src/dir.c b/src/dir.c
Kmods SIG 50e2b3
index 7efb1c6d480846937da5436277b6220dd26f2f7c..c4523648472a088a2477ea9c3ffe7416c498b523 100644
Kmods SIG 50e2b3
--- a/src/dir.c
Kmods SIG 50e2b3
+++ b/src/dir.c
Kmods SIG 50e2b3
@@ -147,7 +147,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
Kmods SIG 50e2b3
 					0);
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 			*uni_name.name = 0x0;
Kmods SIG 50e2b3
-			exfat_get_uniname_from_ext_entry(sb, &dir, dentry,
Kmods SIG 50e2b3
+			exfat_get_uniname_from_ext_entry(sb, &clu, i,
Kmods SIG 50e2b3
 				uni_name.name);
Kmods SIG 50e2b3
 			exfat_utf16_to_nls(sb, &uni_name,
Kmods SIG 50e2b3
 				dir_entry->namebuf.lfn,
Kmods SIG 50e2b3
@@ -911,14 +911,19 @@ enum {
Kmods SIG 50e2b3
 };
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 /*
Kmods SIG 50e2b3
- * return values:
Kmods SIG 50e2b3
- *   >= 0	: return dir entiry position with the name in dir
Kmods SIG 50e2b3
- *   -ENOENT	: entry with the name does not exist
Kmods SIG 50e2b3
- *   -EIO	: I/O error
Kmods SIG 50e2b3
+ * @ei:         inode info of parent directory
Kmods SIG 50e2b3
+ * @p_dir:      directory structure of parent directory
Kmods SIG 50e2b3
+ * @num_entries:entry size of p_uniname
Kmods SIG 50e2b3
+ * @hint_opt:   If p_uniname is found, filled with optimized dir/entry
Kmods SIG 50e2b3
+ *              for traversing cluster chain.
Kmods SIG 50e2b3
+ * @return:
Kmods SIG 50e2b3
+ *   >= 0:      file directory entry position where the name exists
Kmods SIG 50e2b3
+ *   -ENOENT:   entry with the name does not exist
Kmods SIG 50e2b3
+ *   -EIO:      I/O error
Kmods SIG 50e2b3
  */
Kmods SIG 50e2b3
 int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
Kmods SIG 50e2b3
 		struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
Kmods SIG 50e2b3
-		int num_entries, unsigned int type)
Kmods SIG 50e2b3
+		int num_entries, unsigned int type, struct exfat_hint *hint_opt)
Kmods SIG 50e2b3
 {
Kmods SIG 50e2b3
 	int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
Kmods SIG 50e2b3
 	int order, step, name_len = 0;
Kmods SIG 50e2b3
@@ -995,6 +1000,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 			if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) {
Kmods SIG 50e2b3
 				step = DIRENT_STEP_FILE;
Kmods SIG 50e2b3
+				hint_opt->clu = clu.dir;
Kmods SIG 50e2b3
+				hint_opt->eidx = i;
Kmods SIG 50e2b3
 				if (type == TYPE_ALL || type == entry_type) {
Kmods SIG 50e2b3
 					num_ext = ep->dentry.file.num_ext;
Kmods SIG 50e2b3
 					step = DIRENT_STEP_STRM;
Kmods SIG 50e2b3
diff --git a/src/exfat_fs.h b/src/exfat_fs.h
Kmods SIG 50e2b3
index e77fe2f45cf28fe8533276426a73c657446863f6..1d6da61157c9364996da966537da92681cae5e31 100644
Kmods SIG 50e2b3
--- a/src/exfat_fs.h
Kmods SIG 50e2b3
+++ b/src/exfat_fs.h
Kmods SIG 50e2b3
@@ -457,7 +457,7 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
Kmods SIG 50e2b3
 int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
Kmods SIG 50e2b3
 int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
Kmods SIG 50e2b3
 		struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
Kmods SIG 50e2b3
-		int num_entries, unsigned int type);
Kmods SIG 50e2b3
+		int num_entries, unsigned int type, struct exfat_hint *hint_opt);
Kmods SIG 50e2b3
 int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
Kmods SIG 50e2b3
 int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
Kmods SIG 50e2b3
 		int entry, sector_t *sector, int *offset);
Kmods SIG 50e2b3
diff --git a/src/namei.c b/src/namei.c
Kmods SIG 50e2b3
index 1f7b3dc66fcd6fd5507f9d52d73d01cb69433afd..24b41103d1cc08cbfc967cba9d60d14b579a932b 100644
Kmods SIG 50e2b3
--- a/src/namei.c
Kmods SIG 50e2b3
+++ b/src/namei.c
Kmods SIG 50e2b3
@@ -596,6 +596,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
Kmods SIG 50e2b3
 	struct exfat_inode_info *ei = EXFAT_I(dir);
Kmods SIG 50e2b3
 	struct exfat_dentry *ep, *ep2;
Kmods SIG 50e2b3
 	struct exfat_entry_set_cache *es;
Kmods SIG 50e2b3
+	/* for optimized dir & entry to prevent long traverse of cluster chain */
Kmods SIG 50e2b3
+	struct exfat_hint hint_opt;
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	if (qname->len == 0)
Kmods SIG 50e2b3
 		return -ENOENT;
Kmods SIG 50e2b3
@@ -619,7 +621,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	/* search the file name for directories */
Kmods SIG 50e2b3
 	dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
Kmods SIG 50e2b3
-			num_entries, TYPE_ALL);
Kmods SIG 50e2b3
+			num_entries, TYPE_ALL, &hint_opt);
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
 	if (dentry < 0)
Kmods SIG 50e2b3
 		return dentry; /* -error value */
Kmods SIG 50e2b3
@@ -628,6 +630,11 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
Kmods SIG 50e2b3
 	info->entry = dentry;
Kmods SIG 50e2b3
 	info->num_subdirs = 0;
Kmods SIG 50e2b3
 
Kmods SIG 50e2b3
+	/* adjust cdir to the optimized value */
Kmods SIG 50e2b3
+	cdir.dir = hint_opt.clu;
Kmods SIG 50e2b3
+	if (cdir.flags & ALLOC_NO_FAT_CHAIN)
Kmods SIG 50e2b3
+		cdir.size -= dentry / sbi->dentries_per_clu;
Kmods SIG 50e2b3
+	dentry = hint_opt.eidx;
Kmods SIG 50e2b3
 	es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
Kmods SIG 50e2b3
 	if (!es)
Kmods SIG 50e2b3
 		return -EIO;
Kmods SIG 50e2b3
-- 
Kmods SIG 50e2b3
2.31.1
Kmods SIG 50e2b3