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

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