Skip to content

Commit f693dd9

Browse files
hyeongseok-kim901namjaejeon
authored andcommitted
exfat: speed up iterate/lookup by fixing start point of traversing cluster chain
When directory iterate and lookup is called, there's a buggy rewinding of start point for traversing cluster chain to the parent directory entry's first cluster. This caused repeated cluster chain traversing from the first entry of the parent directory that would show worse performance if huge amounts of files exist under the parent directory. Fix not to rewind, make continue from currently referenced cluster and dir entry. Tested with 50,000 files under single directory / 256GB sdcard, with command "time ls -l > /dev/null", Before : 0m08.69s real 0m00.27s user 0m05.91s system After : 0m07.01s real 0m00.25s user 0m04.34s system Signed-off-by: Hyeongseok Kim <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent c024378 commit f693dd9

File tree

3 files changed

+22
-8
lines changed

3 files changed

+22
-8
lines changed

dir.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
148148
0);
149149

150150
*uni_name.name = 0x0;
151-
exfat_get_uniname_from_ext_entry(sb, &dir, dentry,
151+
exfat_get_uniname_from_ext_entry(sb, &clu, i,
152152
uni_name.name);
153153
exfat_utf16_to_nls(sb, &uni_name,
154154
dir_entry->namebuf.lfn,
@@ -922,14 +922,19 @@ enum {
922922
};
923923

924924
/*
925-
* return values:
926-
* >= 0 : return dir entiry position with the name in dir
927-
* -ENOENT : entry with the name does not exist
928-
* -EIO : I/O error
925+
* @ei: inode info of parent directory
926+
* @p_dir: directory structure of parent directory
927+
* @num_entries:entry size of p_uniname
928+
* @hint_opt: If p_uniname is found, filled with optimized dir/entry
929+
* for traversing cluster chain.
930+
* @return:
931+
* >= 0: file directory entry position where the name exists
932+
* -ENOENT: entry with the name does not exist
933+
* -EIO: I/O error
929934
*/
930935
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
931936
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
932-
int num_entries, unsigned int type)
937+
int num_entries, unsigned int type, struct exfat_hint *hint_opt)
933938
{
934939
int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
935940
int order, step, name_len = 0;
@@ -1006,6 +1011,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
10061011

10071012
if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) {
10081013
step = DIRENT_STEP_FILE;
1014+
hint_opt->clu = clu.dir;
1015+
hint_opt->eidx = i;
10091016
if (type == TYPE_ALL || type == entry_type) {
10101017
num_ext = ep->dentry.file.num_ext;
10111018
step = DIRENT_STEP_STRM;

exfat_fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
483483
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
484484
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
485485
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
486-
int num_entries, unsigned int type);
486+
int num_entries, unsigned int type, struct exfat_hint *hint_opt);
487487
int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
488488
int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
489489
int entry, sector_t *sector, int *offset);

namei.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
646646
struct exfat_inode_info *ei = EXFAT_I(dir);
647647
struct exfat_dentry *ep, *ep2;
648648
struct exfat_entry_set_cache *es;
649+
/* for optimized dir & entry to prevent long traverse of cluster chain */
650+
struct exfat_hint hint_opt;
649651

650652
if (qname->len == 0)
651653
return -ENOENT;
@@ -677,7 +679,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
677679

678680
/* search the file name for directories */
679681
dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
680-
num_entries, TYPE_ALL);
682+
num_entries, TYPE_ALL, &hint_opt);
681683

682684
if (dentry < 0)
683685
return dentry; /* -error value */
@@ -686,6 +688,11 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
686688
info->entry = dentry;
687689
info->num_subdirs = 0;
688690

691+
/* adjust cdir to the optimized value */
692+
cdir.dir = hint_opt.clu;
693+
if (cdir.flags & ALLOC_NO_FAT_CHAIN)
694+
cdir.size -= dentry / sbi->dentries_per_clu;
695+
dentry = hint_opt.eidx;
689696
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
690697
if (!es)
691698
return -EIO;

0 commit comments

Comments
 (0)