Skip to content

Commit e298c8a

Browse files
YuezhangMonamjaejeon
authored andcommitted
exfat: hint the empty entry which at the end of cluster chain
After traversing all directory entries, hint the empty directory entry no matter whether or not there are enough empty directory entries. After this commit, hint the empty directory entries like this: 1. Hint the deleted directory entries if enough; 2. Hint the deleted and unused directory entries which at the end of the cluster chain no matter whether enough or not(Add by this commit); 3. If no any empty directory entries, hint the empty directory entries in the new cluster(Add by this commit). This avoids repeated traversal of directory entries, reduces CPU usage, and improves the performance of creating files and directories(especially on low-performance CPUs). Test create 5000 files in a class 4 SD card on imx6q-sabrelite with: for ((i=0;i<5;i++)); do sync time (for ((j=1;j<=1000;j++)); do touch file$((i*1000+j)); done) done The more files, the more performance improvements. Before After Improvement 1~1000 25.360s 22.168s 14.40% 1001~2000 38.242s 28.72ss 33.15% 2001~3000 49.134s 35.037s 40.23% 3001~4000 62.042s 41.624s 49.05% 4001~5000 73.629s 46.772s 57.42% Signed-off-by: Yuezhang Mo <[email protected]> Reviewed-by: Andy Wu <[email protected]> Reviewed-by: Aoyama Wataru <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent ff39899 commit e298c8a

File tree

2 files changed

+43
-16
lines changed

2 files changed

+43
-16
lines changed

fs/exfat/dir.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -905,17 +905,24 @@ static inline void exfat_reset_empty_hint(struct exfat_hint_femp *hint_femp)
905905

906906
static inline void exfat_set_empty_hint(struct exfat_inode_info *ei,
907907
struct exfat_hint_femp *candi_empty, struct exfat_chain *clu,
908-
int dentry, int num_entries)
908+
int dentry, int num_entries, int entry_type)
909909
{
910910
if (ei->hint_femp.eidx == EXFAT_HINT_NONE ||
911911
ei->hint_femp.eidx > dentry) {
912+
int total_entries = EXFAT_B_TO_DEN(i_size_read(&ei->vfs_inode));
913+
912914
if (candi_empty->count == 0) {
913915
candi_empty->cur = *clu;
914916
candi_empty->eidx = dentry;
915917
}
916918

917-
candi_empty->count++;
918-
if (candi_empty->count == num_entries)
919+
if (entry_type == TYPE_UNUSED)
920+
candi_empty->count += total_entries - dentry;
921+
else
922+
candi_empty->count++;
923+
924+
if (candi_empty->count == num_entries ||
925+
candi_empty->count + candi_empty->eidx == total_entries)
919926
ei->hint_femp = *candi_empty;
920927
}
921928
}
@@ -989,7 +996,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
989996
step = DIRENT_STEP_FILE;
990997

991998
exfat_set_empty_hint(ei, &candi_empty, &clu,
992-
dentry, num_entries);
999+
dentry, num_entries,
1000+
entry_type);
9931001

9941002
brelse(bh);
9951003
if (entry_type == TYPE_UNUSED)
@@ -1100,6 +1108,16 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
11001108
goto rewind;
11011109
}
11021110

1111+
/*
1112+
* set the EXFAT_EOF_CLUSTER flag to avoid search
1113+
* from the beginning again when allocated a new cluster
1114+
*/
1115+
if (ei->hint_femp.eidx == EXFAT_HINT_NONE) {
1116+
ei->hint_femp.cur.dir = EXFAT_EOF_CLUSTER;
1117+
ei->hint_femp.eidx = p_dir->size * dentries_per_clu;
1118+
ei->hint_femp.count = 0;
1119+
}
1120+
11031121
/* initialized hint_stat */
11041122
hint_stat->clu = p_dir->dir;
11051123
hint_stat->eidx = 0;

fs/exfat/namei.c

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,18 @@ static int exfat_search_empty_slot(struct super_block *sb,
224224

225225
if (hint_femp->eidx != EXFAT_HINT_NONE) {
226226
dentry = hint_femp->eidx;
227-
if (num_entries <= hint_femp->count) {
228-
hint_femp->eidx = EXFAT_HINT_NONE;
229-
return dentry;
230-
}
231227

228+
/*
229+
* If hint_femp->count is enough, it is needed to check if
230+
* there are actual empty entries.
231+
* Otherwise, and if "dentry + hint_famp->count" is also equal
232+
* to "p_dir->size * dentries_per_clu", it means ENOSPC.
233+
*/
234+
if (dentry + hint_femp->count == p_dir->size * dentries_per_clu &&
235+
num_entries > hint_femp->count)
236+
return -ENOSPC;
237+
238+
hint_femp->eidx = EXFAT_HINT_NONE;
232239
exfat_chain_dup(&clu, &hint_femp->cur);
233240
} else {
234241
exfat_chain_dup(&clu, p_dir);
@@ -293,6 +300,12 @@ static int exfat_search_empty_slot(struct super_block *sb,
293300
}
294301
}
295302

303+
hint_femp->eidx = p_dir->size * dentries_per_clu - num_empty;
304+
hint_femp->count = num_empty;
305+
if (num_empty == 0)
306+
exfat_chain_set(&hint_femp->cur, EXFAT_EOF_CLUSTER, 0,
307+
clu.flags);
308+
296309
return -ENOSPC;
297310
}
298311

@@ -369,15 +382,11 @@ static int exfat_find_empty_entry(struct inode *inode,
369382
if (exfat_ent_set(sb, last_clu, clu.dir))
370383
return -EIO;
371384

372-
if (hint_femp.eidx == EXFAT_HINT_NONE) {
373-
/* the special case that new dentry
374-
* should be allocated from the start of new cluster
375-
*/
376-
hint_femp.eidx = EXFAT_B_TO_DEN_IDX(p_dir->size, sbi);
377-
hint_femp.count = sbi->dentries_per_clu;
378-
385+
if (hint_femp.cur.dir == EXFAT_EOF_CLUSTER)
379386
exfat_chain_set(&hint_femp.cur, clu.dir, 0, clu.flags);
380-
}
387+
388+
hint_femp.count += sbi->dentries_per_clu;
389+
381390
hint_femp.cur.size++;
382391
p_dir->size++;
383392
size = EXFAT_CLU_TO_B(p_dir->size, sbi);

0 commit comments

Comments
 (0)