Commit 7018ec68 authored by Tetsuhiro Kohada's avatar Tetsuhiro Kohada Committed by Namjae Jeon
Browse files

exfat: retain 'VolumeFlags' properly



MediaFailure and VolumeDirty should be retained if these are set before
mounting.

In '3.1.13.3 Media Failure Field' of exfat specification describe:

 If, upon mounting a volume, the value of this field is 1,
 implementations which scan the entire volume for media failures and
 record all failures as "bad" clusters in the FAT (or otherwise resolve
 media failures) may clear the value of  this field to 0.

Therefore, We should not clear MediaFailure without scanning volume.

In '8.1 Recommended Write Ordering' of exfat specification describe:

 Clear the value of the VolumeDirty field to 0, if its value prior to
 the first step was 0.

Therefore, We should not clear VolumeDirty after mounting.
Also rename ERR_MEDIUM to MEDIA_FAILURE.

Signed-off-by: default avatarTetsuhiro Kohada <kohada.t2@gmail.com>
Signed-off-by: default avatarNamjae Jeon <namjae.jeon@samsung.com>
parent 4dc7d35e
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -224,7 +224,8 @@ 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 */
	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 */
@@ -380,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)
+2 −3
Original line number Diff line number Diff line
@@ -14,9 +14,8 @@

#define EXFAT_MAX_FILE_LEN	255

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

#define EXFAT_EOF_CLUSTER	0xFFFFFFFFu
#define EXFAT_BAD_CLUSTER	0xFFFFFFF7u
+2 −2
Original line number Diff line number Diff line
@@ -106,7 +106,7 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
	if (ei->type != TYPE_FILE && ei->type != TYPE_DIR)
		return -EPERM;

	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);

	num_clusters_new = EXFAT_B_TO_CLU_ROUND_UP(i_size_read(inode), sbi);
	num_clusters_phys =
@@ -220,7 +220,7 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
	if (exfat_free_cluster(inode, &clu))
		return -EIO;

	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);

	return 0;
}
+2 −2
Original line number Diff line number Diff line
@@ -39,7 +39,7 @@ static int __exfat_write_inode(struct inode *inode, int sync)
	if (is_dir && ei->dir.dir == sbi->root_dir && ei->entry == -1)
		return 0;

	exfat_set_vol_flags(sb, VOL_DIRTY);
	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);
@@ -167,7 +167,7 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
	}

	if (*clu == EXFAT_EOF_CLUSTER) {
		exfat_set_vol_flags(sb, VOL_DIRTY);
		exfat_set_volume_dirty(sb);

		new_clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
				EXFAT_EOF_CLUSTER : last_clu + 1;
+10 −10
Original line number Diff line number Diff line
@@ -562,10 +562,10 @@ static int exfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
	int err;

	mutex_lock(&EXFAT_SB(sb)->s_lock);
	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);
	err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_FILE,
		&info);
	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);
	if (err)
		goto unlock;

@@ -834,7 +834,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)
	num_entries++;
	brelse(bh);

	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);
	/* update the directory entry */
	if (exfat_remove_entries(dir, &cdir, entry, 0, num_entries)) {
		err = -EIO;
@@ -843,7 +843,7 @@ static int exfat_unlink(struct inode *dir, struct dentry *dentry)

	/* This doesn't modify ei */
	ei->dir.dir = DIR_DELETED;
	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);

	inode_inc_iversion(dir);
	dir->i_mtime = dir->i_atime = current_time(dir);
@@ -873,10 +873,10 @@ static int exfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
	int err;

	mutex_lock(&EXFAT_SB(sb)->s_lock);
	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);
	err = exfat_add_entry(dir, dentry->d_name.name, &cdir, TYPE_DIR,
		&info);
	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);
	if (err)
		goto unlock;

@@ -1001,14 +1001,14 @@ static int exfat_rmdir(struct inode *dir, struct dentry *dentry)
	num_entries++;
	brelse(bh);

	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);
	err = exfat_remove_entries(dir, &cdir, entry, 0, num_entries);
	if (err) {
		exfat_err(sb, "failed to exfat_remove_entries : err(%d)", err);
		goto unlock;
	}
	ei->dir.dir = DIR_DELETED;
	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);

	inode_inc_iversion(dir);
	dir->i_mtime = dir->i_atime = current_time(dir);
@@ -1300,7 +1300,7 @@ static int __exfat_rename(struct inode *old_parent_inode,
	if (ret)
		goto out;

	exfat_set_vol_flags(sb, VOL_DIRTY);
	exfat_set_volume_dirty(sb);

	if (olddir.dir == newdir.dir)
		ret = exfat_rename_file(new_parent_inode, &olddir, dentry,
@@ -1355,7 +1355,7 @@ del_out:
		 */
		new_ei->dir.dir = DIR_DELETED;
	}
	exfat_set_vol_flags(sb, VOL_CLEAN);
	exfat_clear_volume_dirty(sb);
out:
	return ret;
}
Loading