]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
ext4: make s_mount_flags modifications atomic
authorHarshad Shirwadkar <harshadshirwadkar@gmail.com>
Fri, 6 Nov 2020 03:59:09 +0000 (19:59 -0800)
committerTheodore Ts'o <tytso@mit.edu>
Sat, 7 Nov 2020 04:01:05 +0000 (23:01 -0500)
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>
fs/ext4/ext4.h
fs/ext4/fast_commit.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/super.c

index 2a89c5bbb61b8733cd5e458af7c92abbfffd3af1..1b399cafb15ac2f133eef2996ad8c01d7c552d3f 100644 (file)
@@ -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
  */
index ebe5f423f8f2c6358cc104f57ca645561257021c..5cd6630ab1b976d05a77c3e5f1102af54508e518 100644 (file)
@@ -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;
index 80ad5ccc02880a939ad8b6e82430f235bcd567fd..3ed8c048fb12c547775850ba62d364bc08362c20 100644 (file)
@@ -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
index 81a545fd14a3af7d807fc02e6b9de86193ca1e29..a42ca95840f280491b26e8c76555f424311f3584 100644 (file)
@@ -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;
        }
index 000bf70e88ed6d8d780b0843f1670ef28d4c720d..0d8385aea8981c335e97e3ae38518b2322b1a86b 100644 (file)
@@ -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;
        }
index f067e83f149e2853ee01f99af1df5c5167f3e1f4..24af9ed5c3e52583461ce834b1da817ac1f829b7 100644 (file)
@@ -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:"
index 9e2e06ed2c4548d0665a3b5e860ec9edc932cf7c..7bd02c252f7f65a40930bfefbc300c291ac96d1d 100644 (file)
@@ -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;
                }