Commit 84e57d29 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull exfat update from Namjae Jeon:

 - simplify and remove some redundant directory entry code

 - optimize the size of exfat_entry_set_cache and its allocation policy

 - improve the performance for creating files and directories

* tag 'exfat-for-6.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/linkinjeon/exfat:
  exfat: reuse exfat_find_location() to simplify exfat_get_dentry_set()
  exfat: fix overflow in sector and cluster conversion
  exfat: remove i_size_write() from __exfat_truncate()
  exfat: remove argument 'size' from exfat_truncate()
  exfat: remove unnecessary arguments from exfat_find_dir_entry()
  exfat: remove unneeded codes from __exfat_rename()
  exfat: remove call ilog2() from exfat_readdir()
  exfat: replace magic numbers with Macros
  exfat: rename exfat_free_dentry_set() to exfat_put_dentry_set()
  exfat: move exfat_entry_set_cache from heap to stack
  exfat: support dynamic allocate bh for exfat_entry_set_cache
  exfat: reduce the size of exfat_entry_set_cache
  exfat: hint the empty entry which at the end of cluster chain
  exfat: simplify empty entry hint
parents 23dc9c75 36955d36
Loading
Loading
Loading
Loading
+104 −80
Original line number Diff line number Diff line
@@ -33,10 +33,9 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, unsigned short *uniname)
{
	int i;
	struct exfat_entry_set_cache *es;
	struct exfat_entry_set_cache es;

	es = exfat_get_dentry_set(sb, p_dir, entry, ES_ALL_ENTRIES);
	if (!es)
	if (exfat_get_dentry_set(&es, sb, p_dir, entry, ES_ALL_ENTRIES))
		return;

	/*
@@ -45,8 +44,8 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
	 * Third entry  : first file-name entry
	 * So, the index of first file-name dentry should start from 2.
	 */
	for (i = 2; i < es->num_entries; i++) {
		struct exfat_dentry *ep = exfat_get_dentry_cached(es, i);
	for (i = ES_IDX_FIRST_FILENAME; i < es.num_entries; i++) {
		struct exfat_dentry *ep = exfat_get_dentry_cached(&es, i);

		/* end of name entry */
		if (exfat_get_entry_type(ep) != TYPE_EXTEND)
@@ -56,13 +55,13 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
		uniname += EXFAT_FILE_NAME_LEN;
	}

	exfat_free_dentry_set(es, false);
	exfat_put_dentry_set(&es, false);
}

/* read a directory entry from the opened directory */
static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
{
	int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
	int i, dentries_per_clu, num_ext;
	unsigned int type, clu_offset, max_dentries;
	struct exfat_chain dir, clu;
	struct exfat_uni_name uni_name;
@@ -84,11 +83,10 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
			EXFAT_B_TO_CLU(i_size_read(inode), sbi), ei->flags);

	dentries_per_clu = sbi->dentries_per_clu;
	dentries_per_clu_bits = ilog2(dentries_per_clu);
	max_dentries = (unsigned int)min_t(u64, MAX_EXFAT_DENTRIES,
					   (u64)sbi->num_clusters << dentries_per_clu_bits);
				(u64)EXFAT_CLU_TO_DEN(sbi->num_clusters, sbi));

	clu_offset = dentry >> dentries_per_clu_bits;
	clu_offset = EXFAT_DEN_TO_CLU(dentry, sbi);
	exfat_chain_dup(&clu, &dir);

	if (clu.flags == ALLOC_NO_FAT_CHAIN) {
@@ -163,7 +161,7 @@ static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_ent
			dir_entry->entry = dentry;
			brelse(bh);

			ei->hint_bmap.off = dentry >> dentries_per_clu_bits;
			ei->hint_bmap.off = EXFAT_DEN_TO_CLU(dentry, sbi);
			ei->hint_bmap.clu = clu.dir;

			*cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext);
@@ -337,7 +335,7 @@ int exfat_calc_num_entries(struct exfat_uni_name *p_uniname)
		return -EINVAL;

	/* 1 file entry + 1 stream entry + name entries */
	return ((len - 1) / EXFAT_FILE_NAME_LEN + 3);
	return ES_ENTRY_NUM(len);
}

unsigned int exfat_get_entry_type(struct exfat_dentry *ep)
@@ -592,18 +590,18 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es)
	unsigned short chksum = 0;
	struct exfat_dentry *ep;

	for (i = 0; i < es->num_entries; i++) {
	for (i = ES_IDX_FILE; i < es->num_entries; i++) {
		ep = exfat_get_dentry_cached(es, i);
		chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum,
					     chksum_type);
		chksum_type = CS_DEFAULT;
	}
	ep = exfat_get_dentry_cached(es, 0);
	ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
	ep->dentry.file.checksum = cpu_to_le16(chksum);
	es->modified = true;
}

int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync)
int exfat_put_dentry_set(struct exfat_entry_set_cache *es, int sync)
{
	int i, err = 0;

@@ -615,7 +613,10 @@ int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync)
			bforget(es->bh[i]);
		else
			brelse(es->bh[i]);
	kfree(es);

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

	return err;
}

@@ -812,14 +813,14 @@ struct exfat_dentry *exfat_get_dentry_cached(
 *   pointer of entry set on success,
 *   NULL on failure.
 */
struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, unsigned int type)
int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
		struct super_block *sb, struct exfat_chain *p_dir, int entry,
		unsigned int type)
{
	int ret, i, num_bh;
	unsigned int off, byte_offset, clu = 0;
	unsigned int off;
	sector_t sec;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_entry_set_cache *es;
	struct exfat_dentry *ep;
	int num_entries;
	enum exfat_validate_dentry_mode mode = ES_MODE_STARTED;
@@ -827,52 +828,51 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,

	if (p_dir->dir == DIR_DELETED) {
		exfat_err(sb, "access to deleted dentry");
		return NULL;
		return -EIO;
	}

	byte_offset = EXFAT_DEN_TO_B(entry);
	ret = exfat_walk_fat_chain(sb, p_dir, byte_offset, &clu);
	ret = exfat_find_location(sb, p_dir, entry, &sec, &off);
	if (ret)
		return NULL;
		return ret;

	es = kzalloc(sizeof(*es), GFP_KERNEL);
	if (!es)
		return NULL;
	memset(es, 0, sizeof(*es));
	es->sb = sb;
	es->modified = false;

	/* byte offset in cluster */
	byte_offset = EXFAT_CLU_OFFSET(byte_offset, sbi);

	/* byte offset in sector */
	off = EXFAT_BLK_OFFSET(byte_offset, sb);
	es->start_off = off;

	/* sector offset in cluster */
	sec = EXFAT_B_TO_BLK(byte_offset, sb);
	sec += exfat_cluster_to_sector(sbi, clu);
	es->bh = es->__bh;

	bh = sb_bread(sb, sec);
	if (!bh)
		goto free_es;
		return -EIO;
	es->bh[es->num_bh++] = bh;

	ep = exfat_get_dentry_cached(es, 0);
	ep = exfat_get_dentry_cached(es, ES_IDX_FILE);
	if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
		goto free_es;
		goto put_es;

	num_entries = type == ES_ALL_ENTRIES ?
		ep->dentry.file.num_ext + 1 : type;
	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);
			return -ENOMEM;
		}
		es->bh[0] = bh;
	}

	for (i = 1; i < num_bh; i++) {
		/* get the next sector */
		if (exfat_is_last_sector_in_cluster(sbi, sec)) {
			unsigned int clu = exfat_sector_to_cluster(sbi, sec);

			if (p_dir->flags == ALLOC_NO_FAT_CHAIN)
				clu++;
			else if (exfat_get_next_cluster(sb, &clu))
				goto free_es;
				goto put_es;
			sec = exfat_cluster_to_sector(sbi, clu);
		} else {
			sec++;
@@ -880,21 +880,51 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,

		bh = sb_bread(sb, sec);
		if (!bh)
			goto free_es;
			goto put_es;
		es->bh[es->num_bh++] = bh;
	}

	/* validate cached dentries */
	for (i = 1; i < num_entries; i++) {
	for (i = ES_IDX_STREAM; i < num_entries; i++) {
		ep = exfat_get_dentry_cached(es, i);
		if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
			goto free_es;
			goto put_es;
	}
	return es;
	return 0;

free_es:
	exfat_free_dentry_set(es, false);
	return NULL;
put_es:
	exfat_put_dentry_set(es, false);
	return -EIO;
}

static inline void exfat_reset_empty_hint(struct exfat_hint_femp *hint_femp)
{
	hint_femp->eidx = EXFAT_HINT_NONE;
	hint_femp->count = 0;
}

static inline void exfat_set_empty_hint(struct exfat_inode_info *ei,
		struct exfat_hint_femp *candi_empty, struct exfat_chain *clu,
		int dentry, int num_entries, int entry_type)
{
	if (ei->hint_femp.eidx == EXFAT_HINT_NONE ||
	    ei->hint_femp.eidx > dentry) {
		int total_entries = EXFAT_B_TO_DEN(i_size_read(&ei->vfs_inode));

		if (candi_empty->count == 0) {
			candi_empty->cur = *clu;
			candi_empty->eidx = dentry;
		}

		if (entry_type == TYPE_UNUSED)
			candi_empty->count += total_entries - dentry;
		else
			candi_empty->count++;

		if (candi_empty->count == num_entries ||
		    candi_empty->count + candi_empty->eidx == total_entries)
			ei->hint_femp = *candi_empty;
	}
}

enum {
@@ -917,17 +947,21 @@ enum {
 */
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
		struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
		int num_entries, unsigned int type, struct exfat_hint *hint_opt)
		struct exfat_hint *hint_opt)
{
	int i, rewind = 0, dentry = 0, end_eidx = 0, num_ext = 0, len;
	int order, step, name_len = 0;
	int dentries_per_clu, num_empty = 0;
	int dentries_per_clu;
	unsigned int entry_type;
	unsigned short *uniname = NULL;
	struct exfat_chain clu;
	struct exfat_hint *hint_stat = &ei->hint_stat;
	struct exfat_hint_femp candi_empty;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	int num_entries = exfat_calc_num_entries(p_uniname);

	if (num_entries < 0)
		return num_entries;

	dentries_per_clu = sbi->dentries_per_clu;

@@ -939,10 +973,13 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
		end_eidx = dentry;
	}

	candi_empty.eidx = EXFAT_HINT_NONE;
	exfat_reset_empty_hint(&ei->hint_femp);

rewind:
	order = 0;
	step = DIRENT_STEP_FILE;
	exfat_reset_empty_hint(&candi_empty);

	while (clu.dir != EXFAT_EOF_CLUSTER) {
		i = dentry & (dentries_per_clu - 1);
		for (; i < dentries_per_clu; i++, dentry++) {
@@ -962,26 +999,9 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
			    entry_type == TYPE_DELETED) {
				step = DIRENT_STEP_FILE;

				num_empty++;
				if (candi_empty.eidx == EXFAT_HINT_NONE &&
						num_empty == 1) {
					exfat_chain_set(&candi_empty.cur,
						clu.dir, clu.size, clu.flags);
				}

				if (candi_empty.eidx == EXFAT_HINT_NONE &&
						num_empty >= num_entries) {
					candi_empty.eidx =
						dentry - (num_empty - 1);
					WARN_ON(candi_empty.eidx < 0);
					candi_empty.count = num_empty;

					if (ei->hint_femp.eidx ==
							EXFAT_HINT_NONE ||
						candi_empty.eidx <=
							 ei->hint_femp.eidx)
						ei->hint_femp = candi_empty;
				}
				exfat_set_empty_hint(ei, &candi_empty, &clu,
						dentry, num_entries,
						entry_type);

				brelse(bh);
				if (entry_type == TYPE_UNUSED)
@@ -989,17 +1009,14 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
				continue;
			}

			num_empty = 0;
			candi_empty.eidx = EXFAT_HINT_NONE;
			exfat_reset_empty_hint(&candi_empty);

			if (entry_type == TYPE_FILE || entry_type == TYPE_DIR) {
				step = DIRENT_STEP_FILE;
				hint_opt->clu = clu.dir;
				hint_opt->eidx = i;
				if (type == TYPE_ALL || type == entry_type) {
				num_ext = ep->dentry.file.num_ext;
				step = DIRENT_STEP_STRM;
				}
				brelse(bh);
				continue;
			}
@@ -1090,12 +1107,19 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
		rewind = 1;
		dentry = 0;
		clu.dir = p_dir->dir;
		/* reset empty hint */
		num_empty = 0;
		candi_empty.eidx = EXFAT_HINT_NONE;
		goto rewind;
	}

	/*
	 * set the EXFAT_EOF_CLUSTER flag to avoid search
	 * from the beginning again when allocated a new cluster
	 */
	if (ei->hint_femp.eidx == EXFAT_HINT_NONE) {
		ei->hint_femp.cur.dir = EXFAT_EOF_CLUSTER;
		ei->hint_femp.eidx = p_dir->size * dentries_per_clu;
		ei->hint_femp.count = 0;
	}

	/* initialized hint_stat */
	hint_stat->clu = p_dir->dir;
	hint_stat->eidx = 0;
+41 −15
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/fs.h>
#include <linux/ratelimit.h>
#include <linux/nls.h>
#include <linux/blkdev.h>

#define EXFAT_ROOT_INO		1

@@ -41,6 +42,14 @@ enum {
#define ES_2_ENTRIES		2
#define ES_ALL_ENTRIES		0

#define ES_IDX_FILE		0
#define ES_IDX_STREAM		1
#define ES_IDX_FIRST_FILENAME	2
#define EXFAT_FILENAME_ENTRY_NUM(name_len) \
	DIV_ROUND_UP(name_len, EXFAT_FILE_NAME_LEN)
#define ES_IDX_LAST_FILENAME(name_len)	\
	(ES_IDX_FIRST_FILENAME + EXFAT_FILENAME_ENTRY_NUM(name_len) - 1)

#define DIR_DELETED		0xFFFF0321

/* type values */
@@ -62,15 +71,11 @@ enum {
#define TYPE_PADDING		0x0402
#define TYPE_ACLTAB		0x0403
#define TYPE_BENIGN_SEC		0x0800
#define TYPE_ALL		0x0FFF

#define MAX_CHARSET_SIZE	6 /* max size of multi-byte character */
#define MAX_NAME_LENGTH		255 /* max len of file name excluding NULL */
#define MAX_VFSNAME_BUF_SIZE	((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE)

/* Enough size to hold 256 dentry (even 512 Byte sector) */
#define DIR_CACHE_SIZE		(256*sizeof(struct exfat_dentry)/512+1)

#define EXFAT_HINT_NONE		-1
#define EXFAT_MIN_SUBDIR	2

@@ -95,11 +100,17 @@ enum {
/*
 * helpers for block size to dentry size conversion.
 */
#define EXFAT_B_TO_DEN_IDX(b, sbi)	\
	((b) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS))
#define EXFAT_B_TO_DEN(b)		((b) >> DENTRY_SIZE_BITS)
#define EXFAT_DEN_TO_B(b)		((b) << DENTRY_SIZE_BITS)

/*
 * helpers for cluster size to dentry size conversion.
 */
#define EXFAT_CLU_TO_DEN(clu, sbi)	\
	((clu) << ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS))
#define EXFAT_DEN_TO_CLU(dentry, sbi)	\
	((dentry) >> ((sbi)->cluster_size_bits - DENTRY_SIZE_BITS))

/*
 * helpers for fat entry.
 */
@@ -125,6 +136,17 @@ enum {
#define BITS_PER_BYTE_MASK	0x7
#define IGNORED_BITS_REMAINED(clu, clu_base) ((1 << ((clu) - (clu_base))) - 1)

#define ES_ENTRY_NUM(name_len)	(ES_IDX_LAST_FILENAME(name_len) + 1)
/* 19 entries = 1 file entry + 1 stream entry + 17 filename entries */
#define ES_MAX_ENTRY_NUM	ES_ENTRY_NUM(MAX_NAME_LENGTH)

/*
 * 19 entries x 32 bytes/entry = 608 bytes.
 * The 608 bytes are in 3 sectors at most (even 512 Byte sector).
 */
#define DIR_CACHE_SIZE		\
	(DIV_ROUND_UP(EXFAT_DEN_TO_B(ES_MAX_ENTRY_NUM), SECTOR_SIZE) + 1)

struct exfat_dentry_namebuf {
	char *lfn;
	int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */
@@ -166,13 +188,16 @@ struct exfat_hint {

struct exfat_entry_set_cache {
	struct super_block *sb;
	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;
	bool modified;
};

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

struct exfat_dir_entry {
	struct exfat_chain dir;
	int entry;
@@ -375,7 +400,7 @@ static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi,
		sbi->data_start_sector;
}

static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi,
static inline unsigned int exfat_sector_to_cluster(struct exfat_sb_info *sbi,
		sector_t sec)
{
	return ((sec - sbi->data_start_sector) >> sbi->sect_per_clus_bits) +
@@ -423,8 +448,8 @@ int exfat_trim_fs(struct inode *inode, struct fstrim_range *range);

/* file.c */
extern const struct file_operations exfat_file_operations;
int __exfat_truncate(struct inode *inode, loff_t new_size);
void exfat_truncate(struct inode *inode, loff_t size);
int __exfat_truncate(struct inode *inode);
void exfat_truncate(struct inode *inode);
int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
		  struct iattr *attr);
int exfat_getattr(struct user_namespace *mnt_userns, const struct path *path,
@@ -464,15 +489,16 @@ void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es);
int exfat_calc_num_entries(struct exfat_uni_name *p_uniname);
int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
		struct exfat_chain *p_dir, struct exfat_uni_name *p_uniname,
		int num_entries, unsigned int type, struct exfat_hint *hint_opt);
		struct exfat_hint *hint_opt);
int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu);
struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, struct buffer_head **bh);
struct exfat_dentry *exfat_get_dentry_cached(struct exfat_entry_set_cache *es,
		int num);
struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, unsigned int type);
int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync);
int exfat_get_dentry_set(struct exfat_entry_set_cache *es,
		struct super_block *sb, struct exfat_chain *p_dir, int entry,
		unsigned int type);
int exfat_put_dentry_set(struct exfat_entry_set_cache *es, int sync);
int exfat_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);

/* inode.c */
+5 −7
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static int exfat_sanitize_mode(const struct exfat_sb_info *sbi,
}

/* resize the file length */
int __exfat_truncate(struct inode *inode, loff_t new_size)
int __exfat_truncate(struct inode *inode)
{
	unsigned int num_clusters_new, num_clusters_phys;
	unsigned int last_clu = EXFAT_FREE_CLUSTER;
@@ -113,7 +113,7 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)

	exfat_chain_set(&clu, ei->start_clu, num_clusters_phys, ei->flags);

	if (new_size > 0) {
	if (i_size_read(inode) > 0) {
		/*
		 * Truncate FAT chain num_clusters after the first cluster
		 * num_clusters = min(new, phys);
@@ -143,8 +143,6 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
		ei->start_clu = EXFAT_EOF_CLUSTER;
	}

	i_size_write(inode, new_size);

	if (ei->type == TYPE_FILE)
		ei->attr |= ATTR_ARCHIVE;

@@ -189,7 +187,7 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
	return 0;
}

void exfat_truncate(struct inode *inode, loff_t size)
void exfat_truncate(struct inode *inode)
{
	struct super_block *sb = inode->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
@@ -207,7 +205,7 @@ void exfat_truncate(struct inode *inode, loff_t size)
		goto write_size;
	}

	err = __exfat_truncate(inode, i_size_read(inode));
	err = __exfat_truncate(inode);
	if (err)
		goto write_size;

@@ -310,7 +308,7 @@ int exfat_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
		 * __exfat_write_inode() is called from exfat_truncate(), inode
		 * is already written by it, so mark_inode_dirty() is unneeded.
		 */
		exfat_truncate(inode, attr->ia_size);
		exfat_truncate(inode);
		up_write(&EXFAT_I(inode)->truncate_lock);
	} else
		mark_inode_dirty(inode);
+8 −9
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@ int __exfat_write_inode(struct inode *inode, int sync)
{
	unsigned long long on_disk_size;
	struct exfat_dentry *ep, *ep2;
	struct exfat_entry_set_cache *es = NULL;
	struct exfat_entry_set_cache es;
	struct super_block *sb = inode->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_inode_info *ei = EXFAT_I(inode);
@@ -42,11 +42,10 @@ int __exfat_write_inode(struct inode *inode, int sync)
	exfat_set_volume_dirty(sb);

	/* get the directory entry of given file or directory */
	es = exfat_get_dentry_set(sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES);
	if (!es)
	if (exfat_get_dentry_set(&es, sb, &(ei->dir), ei->entry, ES_ALL_ENTRIES))
		return -EIO;
	ep = exfat_get_dentry_cached(es, 0);
	ep2 = exfat_get_dentry_cached(es, 1);
	ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
	ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);

	ep->dentry.file.attr = cpu_to_le16(exfat_make_attr(inode));

@@ -83,8 +82,8 @@ int __exfat_write_inode(struct inode *inode, int sync)
		ep2->dentry.stream.start_clu = EXFAT_FREE_CLUSTER;
	}

	exfat_update_dir_chksum_with_entry_set(es);
	return exfat_free_dentry_set(es, sync);
	exfat_update_dir_chksum_with_entry_set(&es);
	return exfat_put_dentry_set(&es, sync);
}

int exfat_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -358,7 +357,7 @@ static void exfat_write_failed(struct address_space *mapping, loff_t to)
	if (to > i_size_read(inode)) {
		truncate_pagecache(inode, i_size_read(inode));
		inode->i_mtime = inode->i_ctime = current_time(inode);
		exfat_truncate(inode, EXFAT_I(inode)->i_size_aligned);
		exfat_truncate(inode);
	}
}

@@ -622,7 +621,7 @@ void exfat_evict_inode(struct inode *inode)
	if (!inode->i_nlink) {
		i_size_write(inode, 0);
		mutex_lock(&EXFAT_SB(inode->i_sb)->s_lock);
		__exfat_truncate(inode, 0);
		__exfat_truncate(inode);
		mutex_unlock(&EXFAT_SB(inode->i_sb)->s_lock);
	}

+29 −34
Original line number Diff line number Diff line
@@ -224,11 +224,18 @@ static int exfat_search_empty_slot(struct super_block *sb,

	if (hint_femp->eidx != EXFAT_HINT_NONE) {
		dentry = hint_femp->eidx;
		if (num_entries <= hint_femp->count) {
			hint_femp->eidx = EXFAT_HINT_NONE;
			return dentry;
		}

		/*
		 * If hint_femp->count is enough, it is needed to check if
		 * there are actual empty entries.
		 * Otherwise, and if "dentry + hint_famp->count" is also equal
		 * to "p_dir->size * dentries_per_clu", it means ENOSPC.
		 */
		if (dentry + hint_femp->count == p_dir->size * dentries_per_clu &&
		    num_entries > hint_femp->count)
			return -ENOSPC;

		hint_femp->eidx = EXFAT_HINT_NONE;
		exfat_chain_dup(&clu, &hint_femp->cur);
	} else {
		exfat_chain_dup(&clu, p_dir);
@@ -293,6 +300,12 @@ static int exfat_search_empty_slot(struct super_block *sb,
		}
	}

	hint_femp->eidx = p_dir->size * dentries_per_clu - num_empty;
	hint_femp->count = num_empty;
	if (num_empty == 0)
		exfat_chain_set(&hint_femp->cur, EXFAT_EOF_CLUSTER, 0,
				clu.flags);

	return -ENOSPC;
}

@@ -369,15 +382,11 @@ static int exfat_find_empty_entry(struct inode *inode,
			if (exfat_ent_set(sb, last_clu, clu.dir))
				return -EIO;

		if (hint_femp.eidx == EXFAT_HINT_NONE) {
			/* the special case that new dentry
			 * should be allocated from the start of new cluster
			 */
			hint_femp.eidx = EXFAT_B_TO_DEN_IDX(p_dir->size, sbi);
			hint_femp.count = sbi->dentries_per_clu;

		if (hint_femp.cur.dir == EXFAT_EOF_CLUSTER)
			exfat_chain_set(&hint_femp.cur, clu.dir, 0, clu.flags);
		}

		hint_femp.count += sbi->dentries_per_clu;

		hint_femp.cur.size++;
		p_dir->size++;
		size = EXFAT_CLU_TO_B(p_dir->size, sbi);
@@ -588,14 +597,14 @@ static int exfat_create(struct user_namespace *mnt_userns, struct inode *dir,
static int exfat_find(struct inode *dir, struct qstr *qname,
		struct exfat_dir_entry *info)
{
	int ret, dentry, num_entries, count;
	int ret, dentry, count;
	struct exfat_chain cdir;
	struct exfat_uni_name uni_name;
	struct super_block *sb = dir->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_inode_info *ei = EXFAT_I(dir);
	struct exfat_dentry *ep, *ep2;
	struct exfat_entry_set_cache *es;
	struct exfat_entry_set_cache es;
	/* for optimized dir & entry to prevent long traverse of cluster chain */
	struct exfat_hint hint_opt;

@@ -607,10 +616,6 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
	if (ret)
		return ret;

	num_entries = exfat_calc_num_entries(&uni_name);
	if (num_entries < 0)
		return num_entries;

	/* check the validation of hint_stat and initialize it if required */
	if (ei->version != (inode_peek_iversion_raw(dir) & 0xffffffff)) {
		ei->hint_stat.clu = cdir.dir;
@@ -620,9 +625,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
	}

	/* search the file name for directories */
	dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
			num_entries, TYPE_ALL, &hint_opt);

	dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name, &hint_opt);
	if (dentry < 0)
		return dentry; /* -error value */

@@ -635,11 +638,10 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
	if (cdir.flags & ALLOC_NO_FAT_CHAIN)
		cdir.size -= dentry / sbi->dentries_per_clu;
	dentry = hint_opt.eidx;
	es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
	if (!es)
	if (exfat_get_dentry_set(&es, sb, &cdir, dentry, ES_2_ENTRIES))
		return -EIO;
	ep = exfat_get_dentry_cached(es, 0);
	ep2 = exfat_get_dentry_cached(es, 1);
	ep = exfat_get_dentry_cached(&es, ES_IDX_FILE);
	ep2 = exfat_get_dentry_cached(&es, ES_IDX_STREAM);

	info->type = exfat_get_entry_type(ep);
	info->attr = le16_to_cpu(ep->dentry.file.attr);
@@ -668,7 +670,7 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
			     ep->dentry.file.access_time,
			     ep->dentry.file.access_date,
			     0);
	exfat_free_dentry_set(es, false);
	exfat_put_dentry_set(&es, false);

	if (ei->start_clu == EXFAT_FREE_CLUSTER) {
		exfat_fs_error(sb,
@@ -1167,7 +1169,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
	struct exfat_inode_info *new_ei = NULL;
	unsigned int new_entry_type = TYPE_UNUSED;
	int new_entry = 0;
	struct buffer_head *old_bh, *new_bh = NULL;
	struct buffer_head *new_bh = NULL;

	/* check the validity of pointer parameters */
	if (new_path == NULL || strlen(new_path) == 0)
@@ -1183,13 +1185,6 @@ static int __exfat_rename(struct inode *old_parent_inode,
		EXFAT_I(old_parent_inode)->flags);
	dentry = ei->entry;

	ep = exfat_get_dentry(sb, &olddir, dentry, &old_bh);
	if (!ep) {
		ret = -EIO;
		goto out;
	}
	brelse(old_bh);

	/* check whether new dir is existing directory and empty */
	if (new_inode) {
		ret = -EIO;