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 */
}
/* 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)
#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
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 =
if (exfat_free_cluster(inode, &clu))
return -EIO;
- exfat_set_vol_flags(sb, VOL_CLEAN);
+ exfat_clear_volume_dirty(sb);
return 0;
}
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);
}
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;
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;
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;
/* 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);
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;
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);
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,
*/
new_ei->dir.dir = DIR_DELETED;
}
- exfat_set_vol_flags(sb, VOL_CLEAN);
+ exfat_clear_volume_dirty(sb);
out:
return ret;
}
/* If there are some dirty buffers in the bdev inode */
mutex_lock(&sbi->s_lock);
sync_blockdev(sb->s_bdev);
- if (exfat_set_vol_flags(sb, VOL_CLEAN))
+ if (exfat_clear_volume_dirty(sb))
err = -EIO;
mutex_unlock(&sbi->s_lock);
return err;
return 0;
}
-int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flag)
+static int exfat_set_vol_flags(struct super_block *sb, unsigned short new_flags)
{
struct exfat_sb_info *sbi = EXFAT_SB(sb);
struct boot_sector *p_boot = (struct boot_sector *)sbi->boot_bh->b_data;
bool sync;
+ /* retain persistent-flags */
+ new_flags |= sbi->vol_flags_persistent;
+
/* flags are not changed */
- if (sbi->vol_flag == new_flag)
+ if (sbi->vol_flags == new_flags)
return 0;
- sbi->vol_flag = new_flag;
+ sbi->vol_flags = new_flags;
/* skip updating volume dirty flag,
* if this volume has been mounted with read-only
if (sb_rdonly(sb))
return 0;
- p_boot->vol_flags = cpu_to_le16(new_flag);
+ p_boot->vol_flags = cpu_to_le16(new_flags);
- if (new_flag == VOL_DIRTY && !buffer_dirty(sbi->boot_bh))
+ if ((new_flags & VOLUME_DIRTY) && !buffer_dirty(sbi->boot_bh))
sync = true;
else
sync = false;
return 0;
}
+int exfat_set_volume_dirty(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ return exfat_set_vol_flags(sb, sbi->vol_flags | VOLUME_DIRTY);
+}
+
+int exfat_clear_volume_dirty(struct super_block *sb)
+{
+ struct exfat_sb_info *sbi = EXFAT_SB(sb);
+
+ return exfat_set_vol_flags(sb, sbi->vol_flags & ~VOLUME_DIRTY);
+}
+
static int exfat_show_options(struct seq_file *m, struct dentry *root)
{
struct super_block *sb = root->d_sb;
sbi->dentries_per_clu = 1 <<
(sbi->cluster_size_bits - DENTRY_SIZE_BITS);
- sbi->vol_flag = le16_to_cpu(p_boot->vol_flags);
+ sbi->vol_flags = le16_to_cpu(p_boot->vol_flags);
+ sbi->vol_flags_persistent = sbi->vol_flags & (VOLUME_DIRTY | MEDIA_FAILURE);
sbi->clu_srch_ptr = EXFAT_FIRST_CLUSTER;
sbi->used_clusters = EXFAT_CLUSTERS_UNTRACKED;
exfat_err(sb, "bogus data start sector");
return -EINVAL;
}
- if (sbi->vol_flag & VOL_DIRTY)
+ if (sbi->vol_flags & VOLUME_DIRTY)
exfat_warn(sb, "Volume was not properly unmounted. Some data may be corrupt. Please run fsck.");
- if (sbi->vol_flag & ERR_MEDIUM)
+ if (sbi->vol_flags & MEDIA_FAILURE)
exfat_warn(sb, "Medium has reported failures. Some data may be lost.");
/* exFAT file size is limited by a disk volume size */