|
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 |
|