Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7ffa7cf0 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "Merge remote-tracking branch 'remotes/origin/tmp-5030b0ac' into msm-5.4"

parents ffa0e763 c282cef0
Loading
Loading
Loading
Loading
+5 −10
Original line number Diff line number Diff line
@@ -58,8 +58,7 @@ static int exfat_allocate_bitmap(struct super_block *sb,
	need_map_size = ((EXFAT_DATA_CLUSTER_COUNT(sbi) - 1) / BITS_PER_BYTE)
		+ 1;
	if (need_map_size != map_size) {
		exfat_msg(sb, KERN_ERR,
				"bogus allocation bitmap size(need : %u, cur : %lld)",
		exfat_err(sb, "bogus allocation bitmap size(need : %u, cur : %lld)",
			  need_map_size, map_size);
		/*
		 * Only allowed when bogus allocation
@@ -91,7 +90,6 @@ static int exfat_allocate_bitmap(struct super_block *sb,
		}
	}

	sbi->pbr_bh = NULL;
	return 0;
}

@@ -137,8 +135,6 @@ void exfat_free_bitmap(struct exfat_sb_info *sbi)
{
	int i;

	brelse(sbi->pbr_bh);

	for (i = 0; i < sbi->map_sectors; i++)
		__brelse(sbi->vol_amap[i]);

@@ -162,7 +158,7 @@ int exfat_set_bitmap(struct inode *inode, unsigned int clu)
	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);

	set_bit_le(b, sbi->vol_amap[i]->b_data);
	exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode));
	exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));
	return 0;
}

@@ -184,7 +180,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
	b = BITMAP_OFFSET_BIT_IN_SECTOR(sb, ent_idx);

	clear_bit_le(b, sbi->vol_amap[i]->b_data);
	exfat_update_bh(sb, sbi->vol_amap[i], IS_DIRSYNC(inode));
	exfat_update_bh(sbi->vol_amap[i], IS_DIRSYNC(inode));

	if (opts->discard) {
		int ret_discard;
@@ -195,8 +191,7 @@ void exfat_clear_bitmap(struct inode *inode, unsigned int clu)
			(1 << sbi->sect_per_clus_bits), GFP_NOFS, 0);

		if (ret_discard == -EOPNOTSUPP) {
			exfat_msg(sb, KERN_ERR,
				"discard not supported by device, disabling");
			exfat_err(sb, "discard not supported by device, disabling");
			opts->discard = 0;
		}
	}
+0 −11
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
#include "exfat_raw.h"
#include "exfat_fs.h"

#define EXFAT_CACHE_VALID	0
#define EXFAT_MAX_CACHE		16

struct exfat_cache {
@@ -61,16 +60,6 @@ void exfat_cache_shutdown(void)
	kmem_cache_destroy(exfat_cachep);
}

void exfat_cache_init_inode(struct inode *inode)
{
	struct exfat_inode_info *ei = EXFAT_I(inode);

	spin_lock_init(&ei->cache_lru_lock);
	ei->nr_caches = 0;
	ei->cache_valid_id = EXFAT_CACHE_VALID + 1;
	INIT_LIST_HEAD(&ei->cache_lru);
}

static inline struct exfat_cache *exfat_cache_alloc(void)
{
	return kmem_cache_alloc(exfat_cachep, GFP_NOFS);
+117 −166
Original line number Diff line number Diff line
@@ -32,41 +32,36 @@ 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_dentry *ep;
	struct exfat_entry_set_cache *es;

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

	if (es->num_entries < 3)
		goto free_es;

	ep += 2;

	/*
	 * First entry  : file entry
	 * Second entry : stream-extension entry
	 * 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++, ep++) {
	for (i = 2; 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)
			goto free_es;
			break;

		exfat_extract_uni_name(ep, uniname);
		uniname += EXFAT_FILE_NAME_LEN;
	}

free_es:
	kfree(es);
	exfat_free_dentry_set(es, false);
}

/* read a directory entry from the opened directory */
static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
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;
	int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
	unsigned int type, clu_offset;
	sector_t sector;
	struct exfat_chain dir, clu;
@@ -75,7 +70,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
	struct super_block *sb = inode->i_sb;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_inode_info *ei = EXFAT_I(inode);
	unsigned int dentry = ei->rwoffset & 0xFFFFFFFF;
	unsigned int dentry = EXFAT_B_TO_DEN(*cpos) & 0xFFFFFFFF;
	struct buffer_head *bh;

	/* check if the given file ID is opened */
@@ -132,17 +127,18 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
				continue;
			}

			num_ext = ep->dentry.file.num_ext;
			dir_entry->attr = le16_to_cpu(ep->dentry.file.attr);
			exfat_get_entry_time(sbi, &dir_entry->crtime,
					ep->dentry.file.create_tz,
					ep->dentry.file.create_time,
					ep->dentry.file.create_date,
					ep->dentry.file.create_time_ms);
					ep->dentry.file.create_time_cs);
			exfat_get_entry_time(sbi, &dir_entry->mtime,
					ep->dentry.file.modify_tz,
					ep->dentry.file.modify_time,
					ep->dentry.file.modify_date,
					ep->dentry.file.modify_time_ms);
					ep->dentry.file.modify_time_cs);
			exfat_get_entry_time(sbi, &dir_entry->atime,
					ep->dentry.file.access_tz,
					ep->dentry.file.access_time,
@@ -162,12 +158,13 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
				return -EIO;
			dir_entry->size =
				le64_to_cpu(ep->dentry.stream.valid_size);
			dir_entry->entry = dentry;
			brelse(bh);

			ei->hint_bmap.off = dentry >> dentries_per_clu_bits;
			ei->hint_bmap.clu = clu.dir;

			ei->rwoffset = ++dentry;
			*cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext);
			return 0;
		}

@@ -183,7 +180,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
	}

	dir_entry->namebuf.lfn[0] = '\0';
	ei->rwoffset = dentry;
	*cpos = EXFAT_DEN_TO_B(dentry);
	return 0;
}

@@ -247,12 +244,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
	if (err)
		goto unlock;
get_new:
	ei->rwoffset = EXFAT_B_TO_DEN(cpos);

	if (cpos >= i_size_read(inode))
		goto end_of_dir;

	err = exfat_readdir(inode, &de);
	err = exfat_readdir(inode, &cpos, &de);
	if (err) {
		/*
		 * At least we tried to read a sector.  Move cpos to next sector
@@ -267,13 +262,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
		goto end_of_dir;
	}

	cpos = EXFAT_DEN_TO_B(ei->rwoffset);

	if (!nb->lfn[0])
		goto end_of_dir;

	i_pos = ((loff_t)ei->start_clu << 32) |
		((ei->rwoffset - 1) & 0xffffffff);
	i_pos = ((loff_t)ei->start_clu << 32) |	(de.entry & 0xffffffff);
	tmp = exfat_iget(sb, i_pos);
	if (tmp) {
		inum = tmp->i_ino;
@@ -314,7 +306,7 @@ const struct file_operations exfat_dir_operations = {
	.llseek		= generic_file_llseek,
	.read		= generic_read_dir,
	.iterate	= exfat_iterate,
	.fsync		= generic_file_fsync,
	.fsync		= exfat_file_fsync,
};

int exfat_alloc_new_dir(struct inode *inode, struct exfat_chain *clu)
@@ -430,10 +422,12 @@ static void exfat_init_name_entry(struct exfat_dentry *ep,
	ep->dentry.name.flags = 0x0;

	for (i = 0; i < EXFAT_FILE_NAME_LEN; i++) {
		if (*uniname != 0x0) {
			ep->dentry.name.unicode_0_14[i] = cpu_to_le16(*uniname);
		if (*uniname == 0x0)
			break;
			uniname++;
		} else {
			ep->dentry.name.unicode_0_14[i] = 0x0;
		}
	}
}

@@ -461,19 +455,19 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
			&ep->dentry.file.create_tz,
			&ep->dentry.file.create_time,
			&ep->dentry.file.create_date,
			&ep->dentry.file.create_time_ms);
			&ep->dentry.file.create_time_cs);
	exfat_set_entry_time(sbi, &ts,
			&ep->dentry.file.modify_tz,
			&ep->dentry.file.modify_time,
			&ep->dentry.file.modify_date,
			&ep->dentry.file.modify_time_ms);
			&ep->dentry.file.modify_time_cs);
	exfat_set_entry_time(sbi, &ts,
			&ep->dentry.file.access_tz,
			&ep->dentry.file.access_time,
			&ep->dentry.file.access_date,
			NULL);

	exfat_update_bh(sb, bh, IS_DIRSYNC(inode));
	exfat_update_bh(bh, IS_DIRSYNC(inode));
	brelse(bh);

	ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, &sector);
@@ -483,7 +477,7 @@ int exfat_init_dir_entry(struct inode *inode, struct exfat_chain *p_dir,
	exfat_init_stream_entry(ep,
		(type == TYPE_FILE) ? ALLOC_FAT_CHAIN : ALLOC_NO_FAT_CHAIN,
		start_clu, size);
	exfat_update_bh(sb, bh, IS_DIRSYNC(inode));
	exfat_update_bh(bh, IS_DIRSYNC(inode));
	brelse(bh);

	return 0;
@@ -496,7 +490,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
	int ret = 0;
	int i, num_entries;
	sector_t sector;
	unsigned short chksum;
	u16 chksum;
	struct exfat_dentry *ep, *fep;
	struct buffer_head *fbh, *bh;

@@ -505,7 +499,7 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
		return -EIO;

	num_entries = fep->dentry.file.num_ext + 1;
	chksum = exfat_calc_chksum_2byte(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY);
	chksum = exfat_calc_chksum16(fep, DENTRY_SIZE, 0, CS_DIR_ENTRY);

	for (i = 1; i < num_entries; i++) {
		ep = exfat_get_dentry(sb, p_dir, entry + i, &bh, NULL);
@@ -513,13 +507,13 @@ int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
			ret = -EIO;
			goto release_fbh;
		}
		chksum = exfat_calc_chksum_2byte(ep, DENTRY_SIZE, chksum,
		chksum = exfat_calc_chksum16(ep, DENTRY_SIZE, chksum,
				CS_DEFAULT);
		brelse(bh);
	}

	fep->dentry.file.checksum = cpu_to_le16(chksum);
	exfat_update_bh(sb, fbh, IS_DIRSYNC(inode));
	exfat_update_bh(fbh, IS_DIRSYNC(inode));
release_fbh:
	brelse(fbh);
	return ret;
@@ -541,7 +535,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
		return -EIO;

	ep->dentry.file.num_ext = (unsigned char)(num_entries - 1);
	exfat_update_bh(sb, bh, sync);
	exfat_update_bh(bh, sync);
	brelse(bh);

	ep = exfat_get_dentry(sb, p_dir, entry + 1, &bh, &sector);
@@ -550,7 +544,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,

	ep->dentry.stream.name_len = p_uniname->name_len;
	ep->dentry.stream.name_hash = cpu_to_le16(p_uniname->name_hash);
	exfat_update_bh(sb, bh, sync);
	exfat_update_bh(bh, sync);
	brelse(bh);

	for (i = EXFAT_FIRST_CLUSTER; i < num_entries; i++) {
@@ -559,7 +553,7 @@ int exfat_init_ext_entry(struct inode *inode, struct exfat_chain *p_dir,
			return -EIO;

		exfat_init_name_entry(ep, uniname);
		exfat_update_bh(sb, bh, sync);
		exfat_update_bh(bh, sync);
		brelse(bh);
		uniname += EXFAT_FILE_NAME_LEN;
	}
@@ -583,69 +577,44 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
			return -EIO;

		exfat_set_entry_type(ep, TYPE_DELETED);
		exfat_update_bh(sb, bh, IS_DIRSYNC(inode));
		exfat_update_bh(bh, IS_DIRSYNC(inode));
		brelse(bh);
	}

	return 0;
}

int exfat_update_dir_chksum_with_entry_set(struct super_block *sb,
		struct exfat_entry_set_cache *es, int sync)
void exfat_update_dir_chksum_with_entry_set(struct exfat_entry_set_cache *es)
{
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct buffer_head *bh;
	sector_t sec = es->sector;
	unsigned int off = es->offset;
	int chksum_type = CS_DIR_ENTRY, i, num_entries = es->num_entries;
	unsigned int buf_off = (off - es->offset);
	unsigned int remaining_byte_in_sector, copy_entries, clu;
	int chksum_type = CS_DIR_ENTRY, i;
	unsigned short chksum = 0;
	struct exfat_dentry *ep;

	for (i = 0; i < num_entries; i++) {
		chksum = exfat_calc_chksum_2byte(&es->entries[i], DENTRY_SIZE,
			chksum, chksum_type);
	for (i = 0; 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->dentry.file.checksum = cpu_to_le16(chksum);
	es->modified = true;
}

	es->entries[0].dentry.file.checksum = cpu_to_le16(chksum);
int exfat_free_dentry_set(struct exfat_entry_set_cache *es, int sync)
{
	int i, err = 0;

	while (num_entries) {
		/* write per sector base */
		remaining_byte_in_sector = (1 << sb->s_blocksize_bits) - off;
		copy_entries = min_t(int,
			EXFAT_B_TO_DEN(remaining_byte_in_sector),
			num_entries);
		bh = sb_bread(sb, sec);
		if (!bh)
			goto err_out;
		memcpy(bh->b_data + off,
			(unsigned char *)&es->entries[0] + buf_off,
			EXFAT_DEN_TO_B(copy_entries));
		exfat_update_bh(sb, bh, sync);
		brelse(bh);
		num_entries -= copy_entries;
	if (es->modified)
		err = exfat_update_bhs(es->bh, es->num_bh, sync);

		if (num_entries) {
			/* get next sector */
			if (exfat_is_last_sector_in_cluster(sbi, sec)) {
				clu = exfat_sector_to_cluster(sbi, sec);
				if (es->alloc_flag == ALLOC_NO_FAT_CHAIN)
					clu++;
				else if (exfat_get_next_cluster(sb, &clu))
					goto err_out;
				sec = exfat_cluster_to_sector(sbi, clu);
			} else {
				sec++;
			}
			off = 0;
			buf_off += EXFAT_DEN_TO_B(copy_entries);
		}
	}

	return 0;
err_out:
	return -EIO;
	for (i = 0; i < es->num_bh; i++)
		if (err)
			bforget(es->bh[i]);
		else
			brelse(es->bh[i]);
	kfree(es);
	return err;
}

static int exfat_walk_fat_chain(struct super_block *sb,
@@ -720,8 +689,7 @@ static int exfat_dir_readahead(struct super_block *sb, sector_t sec)
		return 0;

	if (sec < sbi->data_start_sector) {
		exfat_msg(sb, KERN_ERR,
			"requested sector is invalid(sect:%llu, root:%llu)",
		exfat_err(sb, "requested sector is invalid(sect:%llu, root:%llu)",
			  (unsigned long long)sec, sbi->data_start_sector);
		return -EIO;
	}
@@ -750,7 +718,7 @@ struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
	sector_t sec;

	if (p_dir->dir == DIR_DELETED) {
		exfat_msg(sb, KERN_ERR, "abnormal access to deleted dentry\n");
		exfat_err(sb, "abnormal access to deleted dentry");
		return NULL;
	}

@@ -821,39 +789,45 @@ static bool exfat_validate_entry(unsigned int type,
	}
}

struct exfat_dentry *exfat_get_dentry_cached(
	struct exfat_entry_set_cache *es, int num)
{
	int off = es->start_off + num * DENTRY_SIZE;
	struct buffer_head *bh = es->bh[EXFAT_B_TO_BLK(off, es->sb)];
	char *p = bh->b_data + EXFAT_BLK_OFFSET(off, es->sb);

	return (struct exfat_dentry *)p;
}

/*
 * Returns a set of dentries for a file or dir.
 *
 * Note that this is a copy (dump) of dentries so that user should
 * call write_entry_set() to apply changes made in this entry set
 * to the real device.
 * Note It provides a direct pointer to bh->data via exfat_get_dentry_cached().
 * User should call exfat_get_dentry_set() after setting 'modified' to apply
 * changes made in this entry set to the real device.
 *
 * in:
 *   sb+p_dir+entry: indicates a file/dir
 *   type:  specifies how many dentries should be included.
 * out:
 *   file_ep: will point the first dentry(= file dentry) on success
 * return:
 *   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,
		struct exfat_dentry **file_ep)
		struct exfat_chain *p_dir, int entry, unsigned int type)
{
	int ret;
	int ret, i, num_bh;
	unsigned int off, byte_offset, clu = 0;
	unsigned int entry_type;
	sector_t sec;
	struct exfat_sb_info *sbi = EXFAT_SB(sb);
	struct exfat_entry_set_cache *es;
	struct exfat_dentry *ep, *pos;
	unsigned char num_entries;
	struct exfat_dentry *ep;
	int num_entries;
	enum exfat_validate_dentry_mode mode = ES_MODE_STARTED;
	struct buffer_head *bh;

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

@@ -862,11 +836,18 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
	if (ret)
		return NULL;

	es = kzalloc(sizeof(*es), GFP_KERNEL);
	if (!es)
		return NULL;
	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);
@@ -874,42 +855,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,

	bh = sb_bread(sb, sec);
	if (!bh)
		return NULL;

	ep = (struct exfat_dentry *)(bh->b_data + off);
	entry_type = exfat_get_entry_type(ep);
		goto free_es;
	es->bh[es->num_bh++] = bh;

	if (entry_type != TYPE_FILE && entry_type != TYPE_DIR)
		goto release_bh;
	ep = exfat_get_dentry_cached(es, 0);
	if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
		goto free_es;

	num_entries = type == ES_ALL_ENTRIES ?
		ep->dentry.file.num_ext + 1 : type;
	es = kmalloc(struct_size(es, entries, num_entries), GFP_KERNEL);
	if (!es)
		goto release_bh;

	es->num_entries = num_entries;
	es->sector = sec;
	es->offset = off;
	es->alloc_flag = p_dir->flags;

	pos = &es->entries[0];

	while (num_entries) {
		if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
			goto free_es;

		/* copy dentry */
		memcpy(pos, ep, sizeof(struct exfat_dentry));

		if (--num_entries == 0)
			break;

		if (((off + DENTRY_SIZE) & (sb->s_blocksize - 1)) <
		    (off & (sb->s_blocksize - 1))) {
	num_bh = EXFAT_B_TO_BLK_ROUND_UP(off + num_entries * DENTRY_SIZE, sb);
	for (i = 1; i < num_bh; i++) {
		/* get the next sector */
		if (exfat_is_last_sector_in_cluster(sbi, sec)) {
				if (es->alloc_flag == ALLOC_NO_FAT_CHAIN)
			if (p_dir->flags == ALLOC_NO_FAT_CHAIN)
				clu++;
			else if (exfat_get_next_cluster(sb, &clu))
				goto free_es;
@@ -918,28 +879,22 @@ struct exfat_entry_set_cache *exfat_get_dentry_set(struct super_block *sb,
			sec++;
		}

			brelse(bh);
		bh = sb_bread(sb, sec);
		if (!bh)
			goto free_es;
			off = 0;
			ep = (struct exfat_dentry *)bh->b_data;
		} else {
			ep++;
			off += DENTRY_SIZE;
		}
		pos++;
		es->bh[es->num_bh++] = bh;
	}

	if (file_ep)
		*file_ep = &es->entries[0];
	brelse(bh);
	/* validiate cached dentries */
	for (i = 1; i < num_entries; i++) {
		ep = exfat_get_dentry_cached(es, i);
		if (!exfat_validate_entry(exfat_get_entry_type(ep), &mode))
			goto free_es;
	}
	return es;

free_es:
	kfree(es);
release_bh:
	brelse(bh);
	exfat_free_dentry_set(es, false);
	return NULL;
}

@@ -953,7 +908,6 @@ enum {
/*
 * return values:
 *   >= 0	: return dir entiry position with the name in dir
 *   -EEXIST	: (root dir, ".") it is the root dir itself
 *   -ENOENT	: entry with the name does not exist
 *   -EIO	: I/O error
 */
@@ -1021,11 +975,8 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
					if (ei->hint_femp.eidx ==
							EXFAT_HINT_NONE ||
						candi_empty.eidx <=
							 ei->hint_femp.eidx) {
						memcpy(&ei->hint_femp,
							&candi_empty,
							sizeof(candi_empty));
					}
							 ei->hint_femp.eidx)
						ei->hint_femp = candi_empty;
				}

				brelse(bh);
@@ -1048,7 +999,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
			}

			if (entry_type == TYPE_STREAM) {
				unsigned short name_hash;
				u16 name_hash;

				if (step != DIRENT_STEP_STRM) {
					step = DIRENT_STEP_FILE;
@@ -1158,7 +1109,7 @@ int exfat_find_dir_entry(struct super_block *sb, struct exfat_inode_info *ei,
			ret = exfat_get_next_cluster(sb, &clu.dir);
		}

		if (ret || clu.dir != EXFAT_EOF_CLUSTER) {
		if (ret || clu.dir == EXFAT_EOF_CLUSTER) {
			/* just initialized hint_stat */
			hint_stat->clu = p_dir->dir;
			hint_stat->eidx = 0;
+37 −34
Original line number Diff line number Diff line
@@ -13,8 +13,6 @@
#define EXFAT_SUPER_MAGIC       0x2011BAB0UL
#define EXFAT_ROOT_INO		1

#define EXFAT_SB_DIRTY		0

#define EXFAT_CLUSTERS_UNTRACKED (~0u)

/*
@@ -71,10 +69,8 @@ enum {
#define MAX_NAME_LENGTH		255 /* max len of file name excluding NULL */
#define MAX_VFSNAME_BUF_SIZE	((MAX_NAME_LENGTH + 1) * MAX_CHARSET_SIZE)

#define FAT_CACHE_SIZE		128
#define FAT_CACHE_HASH_SIZE	64
#define BUF_CACHE_SIZE		256
#define BUF_CACHE_HASH_SIZE	64
/* 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
@@ -132,14 +128,14 @@ enum {

struct exfat_dentry_namebuf {
	char *lfn;
	int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */
	int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */
};

/* unicode name structure */
struct exfat_uni_name {
	/* +3 for null and for converting */
	unsigned short name[MAX_NAME_LENGTH + 3];
	unsigned short name_hash;
	u16 name_hash;
	unsigned char name_len;
};

@@ -170,14 +166,12 @@ struct exfat_hint {
};

struct exfat_entry_set_cache {
	/* sector number that contains file_entry */
	sector_t sector;
	/* byte offset in the sector */
	unsigned int offset;
	/* flag in stream entry. 01 for cluster chain, 03 for contig. */
	int alloc_flag;
	struct super_block *sb;
	bool modified;
	unsigned int start_off;
	int num_bh;
	struct buffer_head *bh[DIR_CACHE_SIZE];
	unsigned int num_entries;
	struct exfat_dentry entries[];
};

struct exfat_dir_entry {
@@ -230,8 +224,9 @@ struct exfat_sb_info {
	unsigned int num_FAT_sectors; /* num of FAT sectors */
	unsigned int root_dir; /* root dir cluster */
	unsigned int dentries_per_clu; /* num of dentries per cluster */
	unsigned int vol_flag; /* volume dirty flag */
	struct buffer_head *pbr_bh; /* buffer_head of PBR sector */
	unsigned int vol_flags; /* volume flags */
	unsigned int vol_flags_persistent; /* volume flags to retain */
	struct buffer_head *boot_bh; /* buffer_head of BOOT sector */

	unsigned int map_clu; /* allocation bitmap start cluster */
	unsigned int map_sectors; /* num of allocation bitmap sectors */
@@ -242,7 +237,6 @@ struct exfat_sb_info {
	unsigned int clu_srch_ptr; /* cluster search pointer */
	unsigned int used_clusters; /* number of used clusters */

	unsigned long s_state;
	struct mutex s_lock; /* superblock lock */
	struct exfat_mount_options options;
	struct nls_table *nls_io; /* Charset used for input and display */
@@ -254,6 +248,8 @@ struct exfat_sb_info {
	struct rcu_head rcu;
};

#define EXFAT_CACHE_VALID	0

/*
 * EXFAT file system inode in-memory data
 */
@@ -269,8 +265,6 @@ struct exfat_inode_info {
	 * the validation of hint_stat.
	 */
	unsigned int version;
	/* file offset or dentry index for readdir */
	loff_t rwoffset;

	/* hint for cluster last accessed */
	struct exfat_hint hint_bmap;
@@ -375,7 +369,7 @@ static inline bool exfat_is_last_sector_in_cluster(struct exfat_sb_info *sbi,
static inline sector_t exfat_cluster_to_sector(struct exfat_sb_info *sbi,
		unsigned int clus)
{
	return ((clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) +
	return ((sector_t)(clus - EXFAT_RESERVED_CLUSTERS) << sbi->sect_per_clus_bits) +
		sbi->data_start_sector;
}

@@ -387,7 +381,8 @@ static inline int exfat_sector_to_cluster(struct exfat_sb_info *sbi,
}

/* super.c */
int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag);
int exfat_set_volume_dirty(struct super_block *sb);
int exfat_clear_volume_dirty(struct super_block *sb);

/* fatent.c */
#define exfat_get_next_cluster(sb, pclu) exfat_ent_get(sb, *(pclu), pclu)
@@ -424,6 +419,7 @@ void exfat_truncate(struct inode *inode, loff_t size);
int exfat_setattr(struct dentry *dentry, struct iattr *attr);
int exfat_getattr(const struct path *path, struct kstat *stat,
		unsigned int request_mask, unsigned int query_flags);
int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);

/* namei.c */
extern const struct dentry_operations exfat_dentry_ops;
@@ -432,7 +428,6 @@ extern const struct dentry_operations exfat_utf8_dentry_ops;
/* cache.c */
int exfat_cache_init(void);
void exfat_cache_shutdown(void);
void exfat_cache_init_inode(struct inode *inode);
void exfat_cache_inval_inode(struct inode *inode);
int exfat_get_cluster(struct inode *inode, unsigned int cluster,
		unsigned int *fclus, unsigned int *dclus,
@@ -451,8 +446,7 @@ int exfat_remove_entries(struct inode *inode, struct exfat_chain *p_dir,
		int entry, int order, int num_entries);
int exfat_update_dir_chksum(struct inode *inode, struct exfat_chain *p_dir,
		int entry);
int exfat_update_dir_chksum_with_entry_set(struct super_block *sb,
		struct exfat_entry_set_cache *es, int sync);
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,
@@ -463,9 +457,11 @@ int exfat_find_location(struct super_block *sb, struct exfat_chain *p_dir,
struct exfat_dentry *exfat_get_dentry(struct super_block *sb,
		struct exfat_chain *p_dir, int entry, struct buffer_head **bh,
		sector_t *sector);
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,
		struct exfat_dentry **file_ep);
		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_count_dir_entries(struct super_block *sb, struct exfat_chain *p_dir);

/* inode.c */
@@ -492,8 +488,6 @@ int exfat_nls_to_utf16(struct super_block *sb,
		struct exfat_uni_name *uniname, int *p_lossy);
int exfat_create_upcase_table(struct super_block *sb);
void exfat_free_upcase_table(struct exfat_sb_info *sbi);
unsigned short exfat_high_surrogate(unicode_t u);
unsigned short exfat_low_surrogate(unicode_t u);

/* exfat/misc.c */
void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
@@ -505,13 +499,22 @@ void __exfat_fs_error(struct super_block *sb, int report, const char *fmt, ...)
		fmt, ## args)
void exfat_msg(struct super_block *sb, const char *lv, const char *fmt, ...)
		__printf(3, 4) __cold;
#define exfat_err(sb, fmt, ...)						\
	exfat_msg(sb, KERN_ERR, fmt, ##__VA_ARGS__)
#define exfat_warn(sb, fmt, ...)					\
	exfat_msg(sb, KERN_WARNING, fmt, ##__VA_ARGS__)
#define exfat_info(sb, fmt, ...)					\
	exfat_msg(sb, KERN_INFO, fmt, ##__VA_ARGS__)

void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		u8 tz, __le16 time, __le16 date, u8 time_ms);
		u8 tz, __le16 time, __le16 date, u8 time_cs);
void exfat_truncate_atime(struct timespec64 *ts);
void exfat_set_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
		u8 *tz, __le16 *time, __le16 *date, u8 *time_ms);
unsigned short exfat_calc_chksum_2byte(void *data, int len,
		unsigned short chksum, int type);
void exfat_update_bh(struct super_block *sb, struct buffer_head *bh, int sync);
		u8 *tz, __le16 *time, __le16 *date, u8 *time_cs);
u16 exfat_calc_chksum16(void *data, int len, u16 chksum, int type);
u32 exfat_calc_chksum32(void *data, int len, u32 chksum, int type);
void exfat_update_bh(struct buffer_head *bh, int sync);
int exfat_update_bhs(struct buffer_head **bhs, int nr_bhs, int sync);
void exfat_chain_set(struct exfat_chain *ec, unsigned int dir,
		unsigned int size, unsigned char flags);
void exfat_chain_dup(struct exfat_chain *dup, struct exfat_chain *ec);
+34 −54
Original line number Diff line number Diff line
@@ -8,12 +8,14 @@

#include <linux/types.h>

#define PBR_SIGNATURE		0xAA55
#define BOOT_SIGNATURE		0xAA55
#define EXBOOT_SIGNATURE	0xAA550000
#define STR_EXFAT		"EXFAT   "	/* size should be 8 */

#define EXFAT_MAX_FILE_LEN	255

#define VOL_CLEAN		0x0000
#define VOL_DIRTY		0x0002
#define VOLUME_DIRTY		0x0002
#define MEDIA_FAILURE		0x0004

#define EXFAT_EOF_CLUSTER	0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER	0xFFFFFFF7u
@@ -55,7 +57,7 @@

/* checksum types */
#define CS_DIR_ENTRY		0
#define CS_PBR_SECTOR		1
#define CS_BOOT_SECTOR		1
#define CS_DEFAULT		2

/* file attributes */
@@ -69,22 +71,18 @@
#define ATTR_RWMASK		(ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME | \
				 ATTR_SUBDIR | ATTR_ARCHIVE)

#define PBR64_JUMP_BOOT_LEN		3
#define PBR64_OEM_NAME_LEN		8
#define PBR64_RESERVED_LEN		53
#define BOOTSEC_JUMP_BOOT_LEN		3
#define BOOTSEC_FS_NAME_LEN		8
#define BOOTSEC_OLDBPB_LEN		53

#define EXFAT_FILE_NAME_LEN		15

/* EXFAT BIOS parameter block (64 bytes) */
struct bpb64 {
	__u8 jmp_boot[PBR64_JUMP_BOOT_LEN];
	__u8 oem_name[PBR64_OEM_NAME_LEN];
	__u8 res_zero[PBR64_RESERVED_LEN];
} __packed;

/* EXFAT EXTEND BIOS parameter block (56 bytes) */
struct bsx64 {
	__le64 vol_offset;
/* EXFAT: Main and Backup Boot Sector (512 bytes) */
struct boot_sector {
	__u8	jmp_boot[BOOTSEC_JUMP_BOOT_LEN];
	__u8	fs_name[BOOTSEC_FS_NAME_LEN];
	__u8	must_be_zero[BOOTSEC_OLDBPB_LEN];
	__le64	partition_offset;
	__le64	vol_length;
	__le32	fat_offset;
	__le32	fat_length;
@@ -92,32 +90,14 @@ struct bsx64 {
	__le32	clu_count;
	__le32	root_cluster;
	__le32	vol_serial;
	__u8 fs_version[2];
	__u8	fs_revision[2];
	__le16	vol_flags;
	__u8	sect_size_bits;
	__u8	sect_per_clus_bits;
	__u8	num_fats;
	__u8 phy_drv_no;
	__u8 perc_in_use;
	__u8 reserved2[7];
} __packed;

/* EXFAT PBR[BPB+BSX] (120 bytes) */
struct pbr64 {
	struct bpb64 bpb;
	struct bsx64 bsx;
} __packed;

/* Common PBR[Partition Boot Record] (512 bytes) */
struct pbr {
	union {
		__u8 raw[64];
		struct bpb64 f64;
	} bpb;
	union {
		__u8 raw[56];
		struct bsx64 f64;
	} bsx;
	__u8	drv_sel;
	__u8	percent_in_use;
	__u8	reserved[7];
	__u8	boot_code[390];
	__le16	signature;
} __packed;
@@ -136,8 +116,8 @@ struct exfat_dentry {
			__le16 modify_date;
			__le16 access_time;
			__le16 access_date;
			__u8 create_time_ms;
			__u8 modify_time_ms;
			__u8 create_time_cs;
			__u8 modify_time_cs;
			__u8 create_tz;
			__u8 modify_tz;
			__u8 access_tz;
Loading