mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-28 00:35:01 +00:00
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 <Yuezhang.Mo@sony.com> Reviewed-by: Aoyama Wataru <wataru.aoyama@sony.com> Reviewed-by: Daniel Palmer <daniel.palmer@sony.com> Reviewed-by: Sungjong Seo <sj1557.seo@samsung.com> Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
parent
6b151eb5df
commit
8a3f5711ad
@ -148,7 +148,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);
|
||||
@ -256,7 +257,7 @@ static int exfat_iterate(struct file *file, 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;
|
||||
|
@ -204,7 +204,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;
|
||||
@ -290,7 +292,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;
|
||||
|
@ -288,8 +288,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,
|
||||
@ -381,7 +395,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);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -613,15 +630,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);
|
||||
|
Loading…
Reference in New Issue
Block a user