Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
exfat: speed up iterate/lookup by fixing start point of traversing cl…
Browse files Browse the repository at this point in the history
…uster 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]>
  • Loading branch information
hyeongseok-kim901 authored and namjaejeon committed Apr 27, 2021
1 parent 23befe4 commit c6e2f52
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 8 deletions.
19 changes: 13 additions & 6 deletions fs/exfat/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
0);

*uni_name.name = 0x0;
exfat_get_uniname_from_ext_entry(sb, &dir, dentry,
exfat_get_uniname_from_ext_entry(sb, &clu, i,
uni_name.name);
exfat_utf16_to_nls(sb, &uni_name,
dir_entry->namebuf.lfn,
Expand Down Expand Up @@ -911,14 +911,19 @@ enum {
};

/*
* return values:
* >= 0 : return dir entiry position with the name in dir
* -ENOENT : entry with the name does not exist
* -EIO : I/O error
* @ei: inode info of parent directory
* @p_dir: directory structure of parent directory
* @num_entries:entry size of p_uniname
* @hint_opt: If p_uniname is found, filled with optimized dir/entry
* for traversing cluster chain.
* @return:
* >= 0: file directory entry position where the name exists
* -ENOENT: entry with the name does not exist
* -EIO: I/O error
*/
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
int num_entries, unsigned int type)
int num_entries, unsigned int type, struct exfat_hint *hint_opt)
{
int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
int order, step, name_len = 0;
Expand Down Expand Up @@ -995,6 +1000,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,

if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) {
step = DIRENT_STEP_FILE;
hint_opt->clu = clu.dir;
hint_opt->eidx = i;
if (type == TYPE_ALL || type == entry_type) {
num_ext = ep->dentry.file.num_ext;
step = DIRENT_STEP_STRM;
Expand Down
2 changes: 1 addition & 1 deletion fs/exfat/exfat_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
int num_entries, unsigned int type);
int num_entries, unsigned int type, struct exfat_hint *hint_opt);
int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
int entry, sector_t *sector, int *offset);
Expand Down
9 changes: 8 additions & 1 deletion fs/exfat/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
struct exfat_inode_info *ei = EXFAT_I(dir);
struct exfat_dentry *ep, *ep2;
struct exfat_entry_set_cache *es;
/* for optimized dir & entry to prevent long traverse of cluster chain */
struct exfat_hint hint_opt;

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

/* search the file name for directories */
dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
num_entries, TYPE_ALL);
num_entries, TYPE_ALL, &hint_opt);

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

/* adjust cdir to the optimized value */
cdir.dir = hint_opt.clu;
if (cdir.flags & ALLOC_NO_FAT_CHAIN)
cdir.size -= dentry / sbi->dentries_per_clu;
dentry = hint_opt.eidx;
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
if (!es)
return -EIO;
Expand Down

0 comments on commit c6e2f52

Please sign in to comment.