Skip to content

Commit 8a3f571

Browse files
YuezhangMonamjaejeon
authored andcommitted
exfat: reduce FAT chain traversal
Before this commit, ->dir and ->entry of exfat_inode_info record the first cluster of the parent directory and the directory entry index starting from this cluster. The directory entry set will be gotten during write-back-inode/rmdir/ unlink/rename. If the clusters of the parent directory are not continuous, the FAT chain will be traversed from the first cluster of the parent directory to find the cluster where ->entry is located. After this commit, ->dir records the cluster where the first directory entry in the directory entry set is located, and ->entry records the directory entry index in the cluster, so that there is almost no need to access the FAT when getting the directory entry set. Signed-off-by: Yuezhang Mo <[email protected]> Reviewed-by: Aoyama Wataru <[email protected]> Reviewed-by: Daniel Palmer <[email protected]> Reviewed-by: Sungjong Seo <[email protected]> Signed-off-by: Namjae Jeon <[email protected]>
1 parent 6b151eb commit 8a3f571

File tree

3 files changed

+32
-9
lines changed

3 files changed

+32
-9
lines changed

fs/exfat/dir.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
148148
ep = exfat_get_dentry(sb, &clu, i + 1, &bh);
149149
if (!ep)
150150
return -EIO;
151-
dir_entry->entry = dentry;
151+
dir_entry->entry = i;
152+
dir_entry->dir = clu;
152153
brelse(bh);
153154

154155
ei->hint_bmap.off = EXFAT_DEN_TO_CLU(dentry, sbi);
@@ -256,7 +257,7 @@ static int exfat_iterate(struct file *file, struct dir_context *ctx)
256257
if (!nb->lfn[0])
257258
goto end_of_dir;
258259

259-
i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff);
260+
i_pos = ((loff_t)de.dir.dir << 32) | (de.entry & 0xffffffff);
260261
tmp = exfat_iget(sb, i_pos);
261262
if (tmp) {
262263
inum = tmp->i_ino;

fs/exfat/exfat_fs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,9 @@ struct exfat_entry_set_cache {
204204
#define IS_DYNAMIC_ES(es) ((es)->__bh != (es)->bh)
205205

206206
struct exfat_dir_entry {
207+
/* the cluster where file dentry is located */
207208
struct exfat_chain dir;
209+
/* the index of file dentry in ->dir */
208210
int entry;
209211
unsigned int type;
210212
unsigned int start_clu;
@@ -290,7 +292,9 @@ struct exfat_sb_info {
290292
* EXFAT file system inode in-memory data
291293
*/
292294
struct exfat_inode_info {
295+
/* the cluster where file dentry is located */
293296
struct exfat_chain dir;
297+
/* the index of file dentry in ->dir */
294298
int entry;
295299
unsigned int type;
296300
unsigned short attr;

fs/exfat/namei.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,22 @@ static int exfat_check_max_dentries(struct inode *inode)
288288
return 0;
289289
}
290290

291-
/* find empty directory entry.
292-
* if there isn't any empty slot, expand cluster chain.
291+
/*
292+
* Find an empty directory entry set.
293+
*
294+
* If there isn't any empty slot, expand cluster chain.
295+
*
296+
* in:
297+
* inode: inode of the parent directory
298+
* num_entries: specifies how many dentries in the empty directory entry set
299+
*
300+
* out:
301+
* p_dir: the cluster where the empty directory entry set is located
302+
* es: The found empty directory entry set
303+
*
304+
* return:
305+
* the directory entry index in p_dir is returned on succeeds
306+
* -error code is returned on failure
293307
*/
294308
static int exfat_find_empty_entry(struct inode *inode,
295309
struct exfat_chain *p_dir, int num_entries,
@@ -381,7 +395,10 @@ static int exfat_find_empty_entry(struct inode *inode,
381395
inode->i_blocks += sbi->cluster_size >> 9;
382396
}
383397

384-
return dentry;
398+
p_dir->dir = exfat_sector_to_cluster(sbi, es->bh[0]->b_blocknr);
399+
p_dir->size -= dentry / sbi->dentries_per_clu;
400+
401+
return dentry & (sbi->dentries_per_clu - 1);
385402
}
386403

387404
/*
@@ -613,15 +630,16 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
613630
if (dentry < 0)
614631
return dentry; /* -error value */
615632

616-
info->dir = cdir;
617-
info->entry = dentry;
618-
info->num_subdirs = 0;
619-
620633
/* adjust cdir to the optimized value */
621634
cdir.dir = hint_opt.clu;
622635
if (cdir.flags & ALLOC_NO_FAT_CHAIN)
623636
cdir.size -= dentry / sbi->dentries_per_clu;
624637
dentry = hint_opt.eidx;
638+
639+
info->dir = cdir;
640+
info->entry = dentry;
641+
info->num_subdirs = 0;
642+
625643
if (exfat_get_dentry_set(&es, sb, &cdir, dentry, ES_2_ENTRIES))
626644
return -EIO;
627645
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);

0 commit comments

Comments
 (0)