Skip to content

Commit c6e2f52

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 23befe4 commit c6e2f52

File tree

3 files changed

+22
-8
lines changed

3 files changed

+22
-8
lines changed

fs/exfat/dir.c

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

149149
*uni_name.name = 0x0;
150-
exfat_get_uniname_from_ext_entry(sb, &dir, dentry,
150+
exfat_get_uniname_from_ext_entry(sb, &clu, i,
151151
uni_name.name);
152152
exfat_utf16_to_nls(sb, &uni_name,
153153
dir_entry->namebuf.lfn,
@@ -911,14 +911,19 @@ enum {
911911
};
912912

913913
/*
914-
* return values:
915-
* >= 0 : return dir entiry position with the name in dir
916-
* -ENOENT : entry with the name does not exist
917-
* -EIO : I/O error
914+
* @ei: inode info of parent directory
915+
* @p_dir: directory structure of parent directory
916+
* @num_entries:entry size of p_uniname
917+
* @hint_opt: If p_uniname is found, filled with optimized dir/entry
918+
* for traversing cluster chain.
919+
* @return:
920+
* >= 0: file directory entry position where the name exists
921+
* -ENOENT: entry with the name does not exist
922+
* -EIO: I/O error
918923
*/
919924
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
920925
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
921-
int num_entries, unsigned int type)
926+
int num_entries, unsigned int type, struct exfat_hint *hint_opt)
922927
{
923928
int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
924929
int order, step, name_len = 0;
@@ -995,6 +1000,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
9951000

9961001
if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) {
9971002
step = DIRENT_STEP_FILE;
1003+
hint_opt->clu = clu.dir;
1004+
hint_opt->eidx = i;
9981005
if (type == TYPE_ALL || type == entry_type) {
9991006
num_ext = ep->dentry.file.num_ext;
10001007
step = DIRENT_STEP_STRM;

fs/exfat/exfat_fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
457457
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
458458
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
459459
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
460-
int num_entries, unsigned int type);
460+
int num_entries, unsigned int type, struct exfat_hint *hint_opt);
461461
int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
462462
int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
463463
int entry, sector_t *sector, int *offset);

fs/exfat/namei.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
596596
struct exfat_inode_info *ei = EXFAT_I(dir);
597597
struct exfat_dentry *ep, *ep2;
598598
struct exfat_entry_set_cache *es;
599+
/* for optimized dir & entry to prevent long traverse of cluster chain */
600+
struct exfat_hint hint_opt;
599601

600602
if (qname->len == 0)
601603
return -ENOENT;
@@ -619,7 +621,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
619621

620622
/* search the file name for directories */
621623
dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
622-
num_entries, TYPE_ALL);
624+
num_entries, TYPE_ALL, &hint_opt);
623625

624626
if (dentry < 0)
625627
return dentry; /* -error value */
@@ -628,6 +630,11 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
628630
info->entry = dentry;
629631
info->num_subdirs = 0;
630632

633+
/* adjust cdir to the optimized value */
634+
cdir.dir = hint_opt.clu;
635+
if (cdir.flags & ALLOC_NO_FAT_CHAIN)
636+
cdir.size -= dentry / sbi->dentries_per_clu;
637+
dentry = hint_opt.eidx;
631638
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
632639
if (!es)
633640
return -EIO;

0 commit comments

Comments
 (0)