ext4: make s_mount_flags modifications atomic
Fast commit file system states are recorded in sbi->s_mount_flags. Fast commit expects these bit manipulations to be atomic. This patch adds helpers to make those modifications atomic. Suggested-by: Jan Kara <jack@suse.cz> Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com> Link: https://lore.kernel.org/r/20201106035911.1942128-21-harshadshirwadkar@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Родитель
da0c5d2695
Коммит
9b5f6c9b83
|
@ -1419,16 +1419,6 @@ struct ext4_super_block {
|
|||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
/*
|
||||
* run-time mount flags
|
||||
*/
|
||||
#define EXT4_MF_MNTDIR_SAMPLED 0x0001
|
||||
#define EXT4_MF_FS_ABORTED 0x0002 /* Fatal error detected */
|
||||
#define EXT4_MF_FC_INELIGIBLE 0x0004 /* Fast commit ineligible */
|
||||
#define EXT4_MF_FC_COMMITTING 0x0008 /* File system underoing a fast
|
||||
* commit.
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_FS_ENCRYPTION
|
||||
#define DUMMY_ENCRYPTION_ENABLED(sbi) ((sbi)->s_dummy_enc_policy.policy != NULL)
|
||||
#else
|
||||
|
@ -1463,7 +1453,7 @@ struct ext4_sb_info {
|
|||
struct buffer_head * __rcu *s_group_desc;
|
||||
unsigned int s_mount_opt;
|
||||
unsigned int s_mount_opt2;
|
||||
unsigned int s_mount_flags;
|
||||
unsigned long s_mount_flags;
|
||||
unsigned int s_def_mount_opt;
|
||||
ext4_fsblk_t s_sb_block;
|
||||
atomic64_t s_resv_clusters;
|
||||
|
@ -1691,6 +1681,34 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
|
|||
_v; \
|
||||
})
|
||||
|
||||
/*
|
||||
* run-time mount flags
|
||||
*/
|
||||
enum {
|
||||
EXT4_MF_MNTDIR_SAMPLED,
|
||||
EXT4_MF_FS_ABORTED, /* Fatal error detected */
|
||||
EXT4_MF_FC_INELIGIBLE, /* Fast commit ineligible */
|
||||
EXT4_MF_FC_COMMITTING /* File system underoing a fast
|
||||
* commit.
|
||||
*/
|
||||
};
|
||||
|
||||
static inline void ext4_set_mount_flag(struct super_block *sb, int bit)
|
||||
{
|
||||
set_bit(bit, &EXT4_SB(sb)->s_mount_flags);
|
||||
}
|
||||
|
||||
static inline void ext4_clear_mount_flag(struct super_block *sb, int bit)
|
||||
{
|
||||
clear_bit(bit, &EXT4_SB(sb)->s_mount_flags);
|
||||
}
|
||||
|
||||
static inline int ext4_test_mount_flag(struct super_block *sb, int bit)
|
||||
{
|
||||
return test_bit(bit, &EXT4_SB(sb)->s_mount_flags);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Simulate_fail codes
|
||||
*/
|
||||
|
|
|
@ -261,7 +261,7 @@ void ext4_fc_mark_ineligible(struct super_block *sb, int reason)
|
|||
(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
|
||||
return;
|
||||
|
||||
sbi->s_mount_flags |= EXT4_MF_FC_INELIGIBLE;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
|
||||
WARN_ON(reason >= EXT4_FC_REASON_MAX);
|
||||
sbi->s_fc_stats.fc_ineligible_reason_count[reason]++;
|
||||
}
|
||||
|
@ -294,14 +294,14 @@ void ext4_fc_stop_ineligible(struct super_block *sb)
|
|||
(EXT4_SB(sb)->s_mount_state & EXT4_FC_REPLAY))
|
||||
return;
|
||||
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FC_INELIGIBLE;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
|
||||
atomic_dec(&EXT4_SB(sb)->s_fc_ineligible_updates);
|
||||
}
|
||||
|
||||
static inline int ext4_fc_is_ineligible(struct super_block *sb)
|
||||
{
|
||||
return (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FC_INELIGIBLE) ||
|
||||
atomic_read(&EXT4_SB(sb)->s_fc_ineligible_updates);
|
||||
return (ext4_test_mount_flag(sb, EXT4_MF_FC_INELIGIBLE) ||
|
||||
atomic_read(&EXT4_SB(sb)->s_fc_ineligible_updates));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -349,7 +349,7 @@ static int ext4_fc_track_template(
|
|||
spin_lock(&sbi->s_fc_lock);
|
||||
if (list_empty(&EXT4_I(inode)->i_fc_list))
|
||||
list_add_tail(&EXT4_I(inode)->i_fc_list,
|
||||
(sbi->s_mount_flags & EXT4_MF_FC_COMMITTING) ?
|
||||
(ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING)) ?
|
||||
&sbi->s_fc_q[FC_Q_STAGING] :
|
||||
&sbi->s_fc_q[FC_Q_MAIN]);
|
||||
spin_unlock(&sbi->s_fc_lock);
|
||||
|
@ -402,7 +402,7 @@ static int __track_dentry_update(struct inode *inode, void *arg, bool update)
|
|||
node->fcd_name.len = dentry->d_name.len;
|
||||
|
||||
spin_lock(&sbi->s_fc_lock);
|
||||
if (sbi->s_mount_flags & EXT4_MF_FC_COMMITTING)
|
||||
if (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FC_COMMITTING))
|
||||
list_add_tail(&node->fcd_list,
|
||||
&sbi->s_fc_dentry_q[FC_Q_STAGING]);
|
||||
else
|
||||
|
@ -857,7 +857,7 @@ static int ext4_fc_submit_inode_data_all(journal_t *journal)
|
|||
int ret = 0;
|
||||
|
||||
spin_lock(&sbi->s_fc_lock);
|
||||
sbi->s_mount_flags |= EXT4_MF_FC_COMMITTING;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FC_COMMITTING);
|
||||
list_for_each(pos, &sbi->s_fc_q[FC_Q_MAIN]) {
|
||||
ei = list_entry(pos, struct ext4_inode_info, i_fc_list);
|
||||
ext4_set_inode_state(&ei->vfs_inode, EXT4_STATE_FC_COMMITTING);
|
||||
|
@ -1206,8 +1206,8 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
|
|||
list_splice_init(&sbi->s_fc_q[FC_Q_STAGING],
|
||||
&sbi->s_fc_q[FC_Q_STAGING]);
|
||||
|
||||
sbi->s_mount_flags &= ~EXT4_MF_FC_COMMITTING;
|
||||
sbi->s_mount_flags &= ~EXT4_MF_FC_INELIGIBLE;
|
||||
ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
|
||||
ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
|
||||
|
||||
if (full)
|
||||
sbi->s_fc_bytes = 0;
|
||||
|
|
|
@ -780,13 +780,13 @@ static int ext4_sample_last_mounted(struct super_block *sb,
|
|||
handle_t *handle;
|
||||
int err;
|
||||
|
||||
if (likely(sbi->s_mount_flags & EXT4_MF_MNTDIR_SAMPLED))
|
||||
if (likely(ext4_test_mount_flag(sb, EXT4_MF_MNTDIR_SAMPLED)))
|
||||
return 0;
|
||||
|
||||
if (sb_rdonly(sb) || !sb_start_intwrite_trylock(sb))
|
||||
return 0;
|
||||
|
||||
sbi->s_mount_flags |= EXT4_MF_MNTDIR_SAMPLED;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_MNTDIR_SAMPLED);
|
||||
/*
|
||||
* Sample where the filesystem has been mounted and
|
||||
* store it in the superblock for sysadmin convenience
|
||||
|
|
|
@ -143,7 +143,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
if (sb_rdonly(inode->i_sb)) {
|
||||
/* Make sure that we read updated s_mount_flags value */
|
||||
smp_rmb();
|
||||
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
if (ext4_test_mount_flag(inode->i_sb, EXT4_MF_FS_ABORTED))
|
||||
ret = -EROFS;
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -2442,7 +2442,7 @@ static int mpage_map_and_submit_extent(handle_t *handle,
|
|||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
if (ext4_forced_shutdown(EXT4_SB(sb)) ||
|
||||
EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED))
|
||||
goto invalidate_dirty_pages;
|
||||
/*
|
||||
* Let the uper layers retry transient errors.
|
||||
|
@ -2676,7 +2676,7 @@ static int ext4_writepages(struct address_space *mapping,
|
|||
* the stack trace.
|
||||
*/
|
||||
if (unlikely(ext4_forced_shutdown(EXT4_SB(mapping->host->i_sb)) ||
|
||||
sbi->s_mount_flags & EXT4_MF_FS_ABORTED)) {
|
||||
ext4_test_mount_flag(inode->i_sb, EXT4_MF_FS_ABORTED))) {
|
||||
ret = -EROFS;
|
||||
goto out_writepages;
|
||||
}
|
||||
|
|
|
@ -4477,7 +4477,7 @@ static inline void ext4_mb_show_pa(struct super_block *sb)
|
|||
{
|
||||
ext4_group_t i, ngroups;
|
||||
|
||||
if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED))
|
||||
return;
|
||||
|
||||
ngroups = ext4_get_groups_count(sb);
|
||||
|
@ -4508,7 +4508,7 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
|
|||
{
|
||||
struct super_block *sb = ac->ac_sb;
|
||||
|
||||
if (EXT4_SB(sb)->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED))
|
||||
return;
|
||||
|
||||
mb_debug(sb, "Can't allocate:"
|
||||
|
|
|
@ -686,7 +686,7 @@ static void ext4_handle_error(struct super_block *sb)
|
|||
if (!test_opt(sb, ERRORS_CONT)) {
|
||||
journal_t *journal = EXT4_SB(sb)->s_journal;
|
||||
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
|
||||
if (journal)
|
||||
jbd2_journal_abort(journal, -EIO);
|
||||
}
|
||||
|
@ -904,7 +904,7 @@ void __ext4_abort(struct super_block *sb, const char *function,
|
|||
va_end(args);
|
||||
|
||||
if (sb_rdonly(sb) == 0) {
|
||||
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
|
||||
if (EXT4_SB(sb)->s_journal)
|
||||
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
||||
|
||||
|
@ -2153,7 +2153,7 @@ static int handle_mount_opt(struct super_block *sb, char *opt, int token,
|
|||
ext4_msg(sb, KERN_WARNING, "Ignoring removed %s option", opt);
|
||||
return 1;
|
||||
case Opt_abort:
|
||||
sbi->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
||||
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
|
||||
return 1;
|
||||
case Opt_i_version:
|
||||
sb->s_flags |= SB_I_VERSION;
|
||||
|
@ -4778,8 +4778,8 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
|
|||
INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_MAIN]);
|
||||
INIT_LIST_HEAD(&sbi->s_fc_dentry_q[FC_Q_STAGING]);
|
||||
sbi->s_fc_bytes = 0;
|
||||
sbi->s_mount_flags &= ~EXT4_MF_FC_INELIGIBLE;
|
||||
sbi->s_mount_flags &= ~EXT4_MF_FC_COMMITTING;
|
||||
ext4_clear_mount_flag(sb, EXT4_MF_FC_INELIGIBLE);
|
||||
ext4_clear_mount_flag(sb, EXT4_MF_FC_COMMITTING);
|
||||
spin_lock_init(&sbi->s_fc_lock);
|
||||
memset(&sbi->s_fc_stats, 0, sizeof(sbi->s_fc_stats));
|
||||
sbi->s_fc_replay_state.fc_regions = NULL;
|
||||
|
@ -5881,7 +5881,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
goto restore_opts;
|
||||
}
|
||||
|
||||
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED)
|
||||
if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED))
|
||||
ext4_abort(sb, EXT4_ERR_ESHUTDOWN, "Abort forced by user");
|
||||
|
||||
sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
|
||||
|
@ -5895,7 +5895,7 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
}
|
||||
|
||||
if ((bool)(*flags & SB_RDONLY) != sb_rdonly(sb)) {
|
||||
if (sbi->s_mount_flags & EXT4_MF_FS_ABORTED) {
|
||||
if (ext4_test_mount_flag(sb, EXT4_MF_FS_ABORTED)) {
|
||||
err = -EROFS;
|
||||
goto restore_opts;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче