Skip to content

Commit

Permalink
exfat: reduce FAT chain traversal
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
YuezhangMo authored and namjaejeon committed Nov 27, 2024
1 parent e15ef9e commit 6033a2f
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 9 deletions.
5 changes: 3 additions & 2 deletions dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,8 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
ep = exfat_get_dentry(sb, &clu, i + 1, &bh);
if (!ep)
return -EIO;
dir_entry->entry = dentry;
dir_entry->entry = i;
dir_entry->dir = clu;
brelse(bh);

ei->hint_bmap.off = EXFAT_DEN_TO_CLU(dentry, sbi);
Expand Down Expand Up @@ -257,7 +258,7 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
if (!nb->lfn[0])
goto end_of_dir;

i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff);
i_pos = ((loff_t)de.dir.dir << 32) | (de.entry & 0xffffffff);
tmp = exfat_iget(sb, i_pos);
if (tmp) {
inum = tmp->i_ino;
Expand Down
4 changes: 4 additions & 0 deletions exfat_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,9 @@ struct exfat_entry_set_cache {
#define IS_DYNAMIC_ES(es) ((es)->__bh != (es)->bh)

struct exfat_dir_entry {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned int start_clu;
Expand Down Expand Up @@ -303,7 +305,9 @@ struct exfat_sb_info {
* EXFAT file system inode in-memory data
*/
struct exfat_inode_info {
/* the cluster where file dentry is located */
struct exfat_chain dir;
/* the index of file dentry in ->dir */
int entry;
unsigned int type;
unsigned short attr;
Expand Down
32 changes: 25 additions & 7 deletions namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,8 +289,22 @@ static int exfat_check_max_dentries(struct inode *inode)
return 0;
}

/* find empty directory entry.
* if there isn't any empty slot, expand cluster chain.
/*
* Find an empty directory entry set.
*
* If there isn't any empty slot, expand cluster chain.
*
* in:
* inode: inode of the parent directory
* num_entries: specifies how many dentries in the empty directory entry set
*
* out:
* p_dir: the cluster where the empty directory entry set is located
* es: The found empty directory entry set
*
* return:
* the directory entry index in p_dir is returned on succeeds
* -error code is returned on failure
*/
static int exfat_find_empty_entry(struct inode *inode,
struct exfat_chain *p_dir, int num_entries,
Expand Down Expand Up @@ -382,7 +396,10 @@ static int exfat_find_empty_entry(struct inode *inode,
inode->i_blocks += sbi->cluster_size >> 9;
}

return dentry;
p_dir->dir = exfat_sector_to_cluster(sbi, es->bh[0]->b_blocknr);
p_dir->size -= dentry / sbi->dentries_per_clu;

return dentry & (sbi->dentries_per_clu - 1);
}

/*
Expand Down Expand Up @@ -637,15 +654,16 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
if (dentry < 0)
return dentry; /* -error value */

info->dir = cdir;
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;

info->dir = cdir;
info->entry = dentry;
info->num_subdirs = 0;

if (exfat_get_dentry_set(&es, sb, &cdir, dentry, ES_2_ENTRIES))
return -EIO;
ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
Expand Down

0 comments on commit 6033a2f

Please sign in to comment.