Commit 9b5f6c9b authored by Harshad Shirwadkar's avatar Harshad Shirwadkar Committed by Theodore Ts'o
Browse files

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: default avatarJan Kara <jack@suse.cz>
Signed-off-by: default avatarHarshad Shirwadkar <harshadshirwadkar@gmail.com>
Link: https://lore.kernel.org/r/20201106035911.1942128-21-harshadshirwadkar@gmail.com


Signed-off-by: default avatarTheodore Ts'o <tytso@mit.edu>
parent da0c5d26
Loading
Loading
Loading
Loading
+29 −11
Original line number Diff line number Diff line
@@ -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
 */
+9 −9
Original line number Diff line number Diff line
@@ -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;
+2 −2
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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;
	}
+2 −2
Original line number Diff line number Diff line
@@ -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;
	}
Loading