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

Commit 01da3a5

Browse files
YuezhangMonamjaejeon
authored andcommitted
exfat: add exfat_get_empty_dentry_set() helper
This helper is used to lookup empty dentry set. If there are no enough empty dentries at the input location, this helper will return the number of dentries that need to be skipped for the next lookup. 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 7b6bab2 commit 01da3a5

File tree

2 files changed

+82
-0
lines changed

2 files changed

+82
-0
lines changed

fs/exfat/dir.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -952,6 +952,85 @@ int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
952952
return -EIO;
953953
}
954954

955+
static int exfat_validate_empty_dentry_set(struct exfat_entry_set_cache *es)
956+
{
957+
struct exfat_dentry *ep;
958+
struct buffer_head *bh;
959+
int i, off;
960+
bool unused_hit = false;
961+
962+
/*
963+
* ONLY UNUSED OR DELETED DENTRIES ARE ALLOWED:
964+
* Although it violates the specification for a deleted entry to
965+
* follow an unused entry, some exFAT implementations could work
966+
* like this. Therefore, to improve compatibility, let's allow it.
967+
*/
968+
for (i = 0; i < es->num_entries; i++) {
969+
ep = exfat_get_dentry_cached(es, i);
970+
if (ep->type == EXFAT_UNUSED) {
971+
unused_hit = true;
972+
} else if (!IS_EXFAT_DELETED(ep->type)) {
973+
if (unused_hit)
974+
goto err_used_follow_unused;
975+
i++;
976+
goto count_skip_entries;
977+
}
978+
}
979+
980+
return 0;
981+
982+
err_used_follow_unused:
983+
off = es->start_off + (i << DENTRY_SIZE_BITS);
984+
bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)];
985+
986+
exfat_fs_error(es->sb,
987+
"in sector %lld, dentry %d should be unused, but 0x%x",
988+
bh->b_blocknr, off >> DENTRY_SIZE_BITS, ep->type);
989+
990+
return -EIO;
991+
992+
count_skip_entries:
993+
es->num_entries = EXFAT_B_TO_DEN(EXFAT_BLK_TO_B(es->num_bh, es->sb) - es->start_off);
994+
for (; i < es->num_entries; i++) {
995+
ep = exfat_get_dentry_cached(es, i);
996+
if (IS_EXFAT_DELETED(ep->type))
997+
break;
998+
}
999+
1000+
return i;
1001+
}
1002+
1003+
/*
1004+
* Get an empty dentry set.
1005+
*
1006+
* in:
1007+
* sb+p_dir+entry: indicates the empty dentry location
1008+
* num_entries: specifies how many empty dentries should be included.
1009+
* out:
1010+
* es: pointer of empty dentry set on success.
1011+
* return:
1012+
* 0 : on success
1013+
* >0 : the dentries are not empty, the return value is the number of
1014+
* dentries to be skipped for the next lookup.
1015+
* <0 : on failure
1016+
*/
1017+
int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
1018+
struct super_block *sb, struct exfat_chain *p_dir,
1019+
int entry, unsigned int num_entries)
1020+
{
1021+
int ret;
1022+
1023+
ret = __exfat_get_dentry_set(es, sb, p_dir, entry, num_entries);
1024+
if (ret < 0)
1025+
return ret;
1026+
1027+
ret = exfat_validate_empty_dentry_set(es);
1028+
if (ret)
1029+
exfat_put_dentry_set(es, false);
1030+
1031+
return ret;
1032+
}
1033+
9551034
static inline void exfat_reset_empty_hint(struct exfat_hint_femp *hint_femp)
9561035
{
9571036
hint_femp->eidx = EXFAT_HINT_NONE;

fs/exfat/exfat_fs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,9 @@ struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
502502
int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
503503
struct super_block *sb, struct exfat_chain *p_dir, int entry,
504504
unsigned int num_entries);
505+
int exfat_get_empty_dentry_set(struct exfat_entry_set_cache *es,
506+
struct super_block *sb, struct exfat_chain *p_dir, int entry,
507+
unsigned int num_entries);
505508
int exfat_put_dentry_set(struct exfat_entry_set_cache *es, int sync);
506509
int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);
507510

0 commit comments

Comments
 (0)