Commit 81ab9cda authored by Yuezhang Mo's avatar Yuezhang Mo Committed by sanglipeng
Browse files

exfat: support dynamic allocate bh for exfat_entry_set_cache

stable inclusion
from stable-v5.10.190
commit bd3bdb9e0d656f760b11d0c638d35d7f7068144d
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I928UI

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=bd3bdb9e0d656f760b11d0c638d35d7f7068144d



--------------------------------

[ Upstream commit a3ff29a9 ]

In special cases, a file or a directory may occupied more than 19
directory entries, pre-allocating 3 bh is not enough. Such as
  - Support vendor secondary directory entry in the future.
  - Since file directory entry is damaged, the SecondaryCount
    field is bigger than 18.

So this commit supports dynamic allocation of bh.

Signed-off-by: default avatarYuezhang Mo <Yuezhang.Mo@sony.com>
Reviewed-by: default avatarAndy Wu <Andy.Wu@sony.com>
Reviewed-by: default avatarAoyama Wataru <wataru.aoyama@sony.com>
Reviewed-by: default avatarSungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
Stable-dep-of: d4233457 ("exfat: check if filename entries exceeds max filename length")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarsanglipeng <sanglipeng1@jd.com>
parent 74946dbe
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -613,6 +613,10 @@ int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync)
			bforget(es->bh[i]);
		else
			brelse(es->bh[i]);

	if (IS_DYNAMIC_ES(es))
		kfree(es->bh);

	kfree(es);
	return err;
}
@@ -848,6 +852,7 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
	/* byte offset in sector */
	off = EXFAT_BLK_OFFSET(byte_offset, sb);
	es->start_off = off;
	es->bh = es->__bh;

	/* sector offset in cluster */
	sec = EXFAT_B_TO_BLK(byte_offset, sb);
@@ -867,6 +872,16 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
	es->num_entries = num_entries;

	num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb);
	if (num_bh > ARRAY_SIZE(es->__bh)) {
		es->bh = kmalloc_array(num_bh, sizeof(*es->bh), GFP_KERNEL);
		if (!es->bh) {
			brelse(bh);
			kfree(es);
			return NULL;
		}
		es->bh[0] = bh;
	}

	for (i = 1; i < num_bh; i++) {
		/* get the next sector */
		if (exfat_is_last_sector_in_cluster(sbi, sec)) {
+4 −1
Original line number Diff line number Diff line
@@ -170,10 +170,13 @@ struct exfat_entry_set_cache {
	bool modified;
	unsigned int start_off;
	int num_bh;
	struct buffer_head *bh[DIR_CACHE_SIZE];
	struct buffer_head *__bh[DIR_CACHE_SIZE];
	struct buffer_head **bh;
	unsigned int num_entries;
};

#define IS_DYNAMIC_ES(es)	((es)->__bh != (es)->bh)

struct exfat_dir_entry {
	struct exfat_chain dir;
	int entry;