Skip to content
This repository was archived by the owner on Nov 8, 2023. It is now read-only.

Commit 7c9ee87

Browse files
dongliang.cuiTreehugger Robot
authored andcommitted
UPSTREAM: exfat: convert exfat_find_empty_entry() to use dentry cache
Before this conversion, each dentry traversed needs to be read from the storage device or page cache. There are at least 16 dentries in a sector. This will result in frequent page cache searches. After this conversion, if all directory entries in a sector are used, the sector only needs to be read once. 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]> (cherry picked from commit af02c72) Change-Id: Ic0540a5f79b0326b3ab1c3cd9a87506a22792ced Signed-off-by: dongliang.cui <[email protected]>
1 parent 3d65f27 commit 7c9ee87

File tree

1 file changed

+42
-84
lines changed

1 file changed

+42
-84
lines changed

fs/exfat/namei.c

Lines changed: 42 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -204,21 +204,16 @@ const struct dentry_operations exfat_utf8_dentry_ops = {
204204
.d_compare = exfat_utf8_d_cmp,
205205
};
206206

207-
/* used only in search empty_slot() */
208-
#define CNT_UNUSED_NOHIT (-1)
209-
#define CNT_UNUSED_HIT (-2)
210207
/* search EMPTY CONTINUOUS "num_entries" entries */
211208
static int exfat_search_empty_slot(struct super_block *sb,
212209
struct exfat_hint_femp *hint_femp, struct exfat_chain *p_dir,
213-
int num_entries)
210+
int num_entries, struct exfat_entry_set_cache *es)
214211
{
215-
int i, dentry, num_empty = 0;
212+
int i, dentry, ret;
216213
int dentries_per_clu;
217-
unsigned int type;
218214
struct exfat_chain clu;
219-
struct exfat_dentry *ep;
220215
struct exfat_sb_info *sbi = EXFAT_SB(sb);
221-
struct buffer_head *bh;
216+
int total_entries = EXFAT_CLU_TO_DEN(p_dir->size, sbi);
222217

223218
dentries_per_clu = sbi->dentries_per_clu;
224219

@@ -231,7 +226,7 @@ static int exfat_search_empty_slot(struct super_block *sb,
231226
* Otherwise, and if "dentry + hint_famp->count" is also equal
232227
* to "p_dir->size * dentries_per_clu", it means ENOSPC.
233228
*/
234-
if (dentry + hint_femp->count == p_dir->size * dentries_per_clu &&
229+
if (dentry + hint_femp->count == total_entries &&
235230
num_entries > hint_femp->count)
236231
return -ENOSPC;
237232

@@ -242,69 +237,41 @@ static int exfat_search_empty_slot(struct super_block *sb,
242237
dentry = 0;
243238
}
244239

245-
while (clu.dir != EXFAT_EOF_CLUSTER) {
240+
while (dentry + num_entries < total_entries &&
241+
clu.dir != EXFAT_EOF_CLUSTER) {
246242
i = dentry & (dentries_per_clu - 1);
247243

248-
for (; i < dentries_per_clu; i++, dentry++) {
249-
ep = exfat_get_dentry(sb, &clu, i, &bh);
250-
if (!ep)
251-
return -EIO;
252-
type = exfat_get_entry_type(ep);
253-
brelse(bh);
254-
255-
if (type == TYPE_UNUSED || type == TYPE_DELETED) {
256-
num_empty++;
257-
if (hint_femp->eidx == EXFAT_HINT_NONE) {
258-
hint_femp->eidx = dentry;
259-
hint_femp->count = CNT_UNUSED_NOHIT;
260-
exfat_chain_set(&hint_femp->cur,
261-
clu.dir, clu.size, clu.flags);
262-
}
263-
264-
if (type == TYPE_UNUSED &&
265-
hint_femp->count != CNT_UNUSED_HIT)
266-
hint_femp->count = CNT_UNUSED_HIT;
244+
ret = exfat_get_empty_dentry_set(es, sb, &clu, i, num_entries);
245+
if (ret < 0)
246+
return ret;
247+
else if (ret == 0)
248+
return dentry;
249+
250+
dentry += ret;
251+
i += ret;
252+
253+
while (i >= dentries_per_clu) {
254+
if (clu.flags == ALLOC_NO_FAT_CHAIN) {
255+
if (--clu.size > 0)
256+
clu.dir++;
257+
else
258+
clu.dir = EXFAT_EOF_CLUSTER;
267259
} else {
268-
if (hint_femp->eidx != EXFAT_HINT_NONE &&
269-
hint_femp->count == CNT_UNUSED_HIT) {
270-
/* unused empty group means
271-
* an empty group which includes
272-
* unused dentry
273-
*/
274-
exfat_fs_error(sb,
275-
"found bogus dentry(%d) beyond unused empty group(%d) (start_clu : %u, cur_clu : %u)",
276-
dentry, hint_femp->eidx,
277-
p_dir->dir, clu.dir);
260+
if (exfat_get_next_cluster(sb, &clu.dir))
278261
return -EIO;
279-
}
280-
281-
num_empty = 0;
282-
hint_femp->eidx = EXFAT_HINT_NONE;
283262
}
284263

285-
if (num_empty >= num_entries) {
286-
/* found and invalidate hint_femp */
287-
hint_femp->eidx = EXFAT_HINT_NONE;
288-
return (dentry - (num_entries - 1));
289-
}
290-
}
291-
292-
if (clu.flags == ALLOC_NO_FAT_CHAIN) {
293-
if (--clu.size > 0)
294-
clu.dir++;
295-
else
296-
clu.dir = EXFAT_EOF_CLUSTER;
297-
} else {
298-
if (exfat_get_next_cluster(sb, &clu.dir))
299-
return -EIO;
264+
i -= dentries_per_clu;
300265
}
301266
}
302267

303-
hint_femp->eidx = p_dir->size * dentries_per_clu - num_empty;
304-
hint_femp->count = num_empty;
305-
if (num_empty == 0)
268+
hint_femp->eidx = dentry;
269+
hint_femp->count = 0;
270+
if (dentry == total_entries || clu.dir == EXFAT_EOF_CLUSTER)
306271
exfat_chain_set(&hint_femp->cur, EXFAT_EOF_CLUSTER, 0,
307272
clu.flags);
273+
else
274+
hint_femp->cur = clu;
308275

309276
return -ENOSPC;
310277
}
@@ -325,7 +292,8 @@ static int exfat_check_max_dentries(struct inode *inode)
325292
* if there isn't any empty slot, expand cluster chain.
326293
*/
327294
static int exfat_find_empty_entry(struct inode *inode,
328-
struct exfat_chain *p_dir, int num_entries)
295+
struct exfat_chain *p_dir, int num_entries,
296+
struct exfat_entry_set_cache *es)
329297
{
330298
int dentry;
331299
unsigned int ret, last_clu;
@@ -344,7 +312,7 @@ static int exfat_find_empty_entry(struct inode *inode,
344312
}
345313

346314
while ((dentry = exfat_search_empty_slot(sb, &hint_femp, p_dir,
347-
num_entries)) < 0) {
315+
num_entries, es)) < 0) {
348316
if (dentry == -EIO)
349317
break;
350318

@@ -515,16 +483,18 @@ static int exfat_add_entry(struct inode *inode, const char *path,
515483
}
516484

517485
/* exfat_find_empty_entry must be called before alloc_cluster() */
518-
dentry = exfat_find_empty_entry(inode, p_dir, num_entries);
486+
dentry = exfat_find_empty_entry(inode, p_dir, num_entries, &es);
519487
if (dentry < 0) {
520488
ret = dentry; /* -EIO or -ENOSPC */
521489
goto out;
522490
}
523491

524492
if (type == TYPE_DIR && !sbi->options.zero_size_dir) {
525493
ret = exfat_alloc_new_dir(inode, &clu);
526-
if (ret)
494+
if (ret) {
495+
exfat_put_dentry_set(&es, false);
527496
goto out;
497+
}
528498
start_clu = clu.dir;
529499
clu_size = sbi->cluster_size;
530500
}
@@ -533,11 +503,6 @@ static int exfat_add_entry(struct inode *inode, const char *path,
533503
/* fill the dos name directory entry information of the created file.
534504
* the first cluster is not determined yet. (0)
535505
*/
536-
537-
ret = exfat_get_empty_dentry_set(&es, sb, p_dir, dentry, num_entries);
538-
if (ret)
539-
goto out;
540-
541506
exfat_init_dir_entry(&es, type, start_clu, clu_size, &ts);
542507
exfat_init_ext_entry(&es, num_entries, &uniname);
543508

@@ -1033,18 +998,13 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
1033998
if (old_es.num_entries < num_new_entries) {
1034999
int newentry;
10351000

1036-
newentry =
1037-
exfat_find_empty_entry(inode, p_dir, num_new_entries);
1001+
newentry = exfat_find_empty_entry(inode, p_dir, num_new_entries,
1002+
&new_es);
10381003
if (newentry < 0) {
10391004
ret = newentry; /* -EIO or -ENOSPC */
10401005
goto put_old_es;
10411006
}
10421007

1043-
ret = exfat_get_empty_dentry_set(&new_es, sb, p_dir, newentry,
1044-
num_new_entries);
1045-
if (ret)
1046-
goto put_old_es;
1047-
10481008
epnew = exfat_get_dentry_cached(&new_es, ES_IDX_FILE);
10491009
*epnew = *epold;
10501010
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
@@ -1094,19 +1054,17 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
10941054
if (num_new_entries < 0)
10951055
return num_new_entries;
10961056

1097-
newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries);
1098-
if (newentry < 0)
1099-
return newentry; /* -EIO or -ENOSPC */
1100-
11011057
ret = exfat_get_dentry_set(&mov_es, sb, p_olddir, oldentry,
11021058
ES_ALL_ENTRIES);
11031059
if (ret)
11041060
return -EIO;
11051061

1106-
ret = exfat_get_empty_dentry_set(&new_es, sb, p_newdir, newentry,
1107-
num_new_entries);
1108-
if (ret)
1062+
newentry = exfat_find_empty_entry(inode, p_newdir, num_new_entries,
1063+
&new_es);
1064+
if (newentry < 0) {
1065+
ret = newentry; /* -EIO or -ENOSPC */
11091066
goto put_mov_es;
1067+
}
11101068

11111069
epmov = exfat_get_dentry_cached(&mov_es, ES_IDX_FILE);
11121070
epnew = exfat_get_dentry_cached(&new_es, ES_IDX_FILE);

0 commit comments

Comments
 (0)