ext4: add ext4_emergency_state() helper function
authorBaokun Li <libaokun1@huawei.com>
Wed, 22 Jan 2025 11:41:26 +0000 (19:41 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Thu, 13 Mar 2025 14:16:34 +0000 (10:16 -0400)
Since both SHUTDOWN and EMERGENCY_RO are emergency states of the ext4 file
system, and they are checked in similar locations, we have added a helper
function, ext4_emergency_state(), to determine whether the current file
system is in one of these two emergency states.

Then, replace calls to ext4_forced_shutdown() with ext4_emergency_state()
in those functions that could potentially trigger write operations.

Signed-off-by: Baokun Li <libaokun1@huawei.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Reviewed-by: Zhang Yi <yi.zhang@huawei.com>
Link: https://patch.msgid.link/20250122114130.229709-4-libaokun@huaweicloud.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
12 files changed:
fs/ext4/ext4.h
fs/ext4/ext4_jbd2.c
fs/ext4/file.c
fs/ext4/fsync.c
fs/ext4/ialloc.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/mmp.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/super.c

index 81cb16b5f8dac89722303737b20d3a996085b4bf..87a8282e5d86ac75b0f37e5bcd3319b780d86751 100644 (file)
@@ -2252,6 +2252,15 @@ static inline int ext4_emergency_ro(struct super_block *sb)
        return test_bit(EXT4_FLAGS_EMERGENCY_RO, &EXT4_SB(sb)->s_ext4_flags);
 }
 
+static inline int ext4_emergency_state(struct super_block *sb)
+{
+       if (unlikely(ext4_forced_shutdown(sb)))
+               return -EIO;
+       if (unlikely(ext4_emergency_ro(sb)))
+               return -EROFS;
+       return 0;
+}
+
 /*
  * Default values for user and/or group using reserved blocks
  */
index da4a8245638364614f0bbac3cd73e87f5e503d98..4e3bd4910f489a1ea63d48ff75fa74e0d708b948 100644 (file)
@@ -63,12 +63,14 @@ static void ext4_put_nojournal(handle_t *handle)
  */
 static int ext4_journal_check_start(struct super_block *sb)
 {
+       int ret;
        journal_t *journal;
 
        might_sleep();
 
-       if (unlikely(ext4_forced_shutdown(sb)))
-               return -EIO;
+       ret = ext4_emergency_state(sb);
+       if (unlikely(ret))
+               return ret;
 
        if (WARN_ON_ONCE(sb_rdonly(sb)))
                return -EROFS;
index a5205149adba352c45b1730483fed5730989b3a8..d0c21e6503c645226d573336afb42d1dc9206db7 100644 (file)
@@ -688,10 +688,12 @@ out:
 static ssize_t
 ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 {
+       int ret;
        struct inode *inode = file_inode(iocb->ki_filp);
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       ret = ext4_emergency_state(inode->i_sb);
+       if (unlikely(ret))
+               return ret;
 
 #ifdef CONFIG_FS_DAX
        if (IS_DAX(inode))
@@ -700,7 +702,6 @@ ext4_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
 
        if (iocb->ki_flags & IOCB_ATOMIC) {
                size_t len = iov_iter_count(from);
-               int ret;
 
                if (len < EXT4_SB(inode->i_sb)->s_awu_min ||
                    len > EXT4_SB(inode->i_sb)->s_awu_max)
@@ -803,11 +804,16 @@ static const struct vm_operations_struct ext4_file_vm_ops = {
 
 static int ext4_file_mmap(struct file *file, struct vm_area_struct *vma)
 {
+       int ret;
        struct inode *inode = file->f_mapping->host;
        struct dax_device *dax_dev = EXT4_SB(inode->i_sb)->s_daxdev;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       if (file->f_mode & FMODE_WRITE)
+               ret = ext4_emergency_state(inode->i_sb);
+       else
+               ret = ext4_forced_shutdown(inode->i_sb) ? -EIO : 0;
+       if (unlikely(ret))
+               return ret;
 
        /*
         * We don't support synchronous mappings for non-DAX files and
@@ -881,8 +887,12 @@ static int ext4_file_open(struct inode *inode, struct file *filp)
 {
        int ret;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       if (filp->f_mode & FMODE_WRITE)
+               ret = ext4_emergency_state(inode->i_sb);
+       else
+               ret = ext4_forced_shutdown(inode->i_sb) ? -EIO : 0;
+       if (unlikely(ret))
+               return ret;
 
        ret = ext4_sample_last_mounted(inode->i_sb, filp->f_path.mnt);
        if (ret)
index b40d3b29f7e5c5b88694794c28198afc2f951aa4..e476c6de307407756eda8e87c71df62f85421244 100644 (file)
@@ -132,20 +132,16 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        bool needs_barrier = false;
        struct inode *inode = file->f_mapping->host;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       ret = ext4_emergency_state(inode->i_sb);
+       if (unlikely(ret))
+               return ret;
 
        ASSERT(ext4_journal_current_handle() == NULL);
 
        trace_ext4_sync_file_enter(file, datasync);
 
-       if (sb_rdonly(inode->i_sb)) {
-               /* Make sure that we read updated s_ext4_flags value */
-               smp_rmb();
-               if (ext4_forced_shutdown(inode->i_sb))
-                       ret = -EROFS;
+       if (sb_rdonly(inode->i_sb))
                goto out;
-       }
 
        if (!EXT4_SB(inode->i_sb)->s_journal) {
                ret = ext4_fsync_nojournal(file, start, end, datasync,
index 9ac5d1426f5441925adfab8e56f5bd8803654b59..543aca2fb75e72903879c116a2e5b0b5b847a35e 100644 (file)
@@ -951,8 +951,9 @@ struct inode *__ext4_new_inode(struct mnt_idmap *idmap,
        sb = dir->i_sb;
        sbi = EXT4_SB(sb);
 
-       if (unlikely(ext4_forced_shutdown(sb)))
-               return ERR_PTR(-EIO);
+       ret2 = ext4_emergency_state(sb);
+       if (unlikely(ret2))
+               return ERR_PTR(ret2);
 
        ngroups = ext4_get_groups_count(sb);
        trace_ext4_request_inode(dir, mode);
index a651a033e518970cb69106b8c503ec35f9142fcc..6c3e8c8ccdf4fddd52cfb02416cee8947a9ffc80 100644 (file)
@@ -233,7 +233,7 @@ static void ext4_write_inline_data(struct inode *inode, struct ext4_iloc *iloc,
        struct ext4_inode *raw_inode;
        int cp_len = 0;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
+       if (unlikely(ext4_emergency_state(inode->i_sb)))
                return;
 
        BUG_ON(!EXT4_I(inode)->i_inline_off);
index 66b89500128a8bd446878d9a1cb22e74741e7d36..fc3e1b474e2c0342881d83f65785007cae7c9a45 100644 (file)
@@ -1150,8 +1150,9 @@ static int ext4_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        unsigned from, to;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       ret = ext4_emergency_state(inode->i_sb);
+       if (unlikely(ret))
+               return ret;
 
        trace_ext4_write_begin(inode, pos, len);
        /*
@@ -2274,7 +2275,7 @@ static int mpage_map_and_submit_extent(handle_t *handle,
                if (err < 0) {
                        struct super_block *sb = inode->i_sb;
 
-                       if (ext4_forced_shutdown(sb))
+                       if (ext4_emergency_state(sb))
                                goto invalidate_dirty_pages;
                        /*
                         * Let the uper layers retry transient errors.
@@ -2600,10 +2601,9 @@ static int ext4_do_writepages(struct mpage_da_data *mpd)
         * *never* be called, so if that ever happens, we would want
         * the stack trace.
         */
-       if (unlikely(ext4_forced_shutdown(mapping->host->i_sb))) {
-               ret = -EROFS;
+       ret = ext4_emergency_state(mapping->host->i_sb);
+       if (unlikely(ret))
                goto out_writepages;
-       }
 
        /*
         * If we have inline data and arrive here, it means that
@@ -2818,8 +2818,9 @@ static int ext4_writepages(struct address_space *mapping,
        int ret;
        int alloc_ctx;
 
-       if (unlikely(ext4_forced_shutdown(sb)))
-               return -EIO;
+       ret = ext4_emergency_state(sb);
+       if (unlikely(ret))
+               return ret;
 
        alloc_ctx = ext4_writepages_down_read(sb);
        ret = ext4_do_writepages(&mpd);
@@ -2859,8 +2860,9 @@ static int ext4_dax_writepages(struct address_space *mapping,
        struct inode *inode = mapping->host;
        int alloc_ctx;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       ret = ext4_emergency_state(inode->i_sb);
+       if (unlikely(ret))
+               return ret;
 
        alloc_ctx = ext4_writepages_down_read(inode->i_sb);
        trace_ext4_writepages(inode, wbc);
@@ -2916,8 +2918,9 @@ static int ext4_da_write_begin(struct file *file, struct address_space *mapping,
        pgoff_t index;
        struct inode *inode = mapping->host;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       ret = ext4_emergency_state(inode->i_sb);
+       if (unlikely(ret))
+               return ret;
 
        index = pos >> PAGE_SHIFT;
 
@@ -5247,8 +5250,9 @@ int ext4_write_inode(struct inode *inode, struct writeback_control *wbc)
        if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
                return 0;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       err = ext4_emergency_state(inode->i_sb);
+       if (unlikely(err))
+               return err;
 
        if (EXT4_SB(inode->i_sb)->s_journal) {
                if (ext4_journal_current_handle()) {
@@ -5370,8 +5374,9 @@ int ext4_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
        const unsigned int ia_valid = attr->ia_valid;
        bool inc_ivers = true;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       error = ext4_emergency_state(inode->i_sb);
+       if (unlikely(error))
+               return error;
 
        if (unlikely(IS_IMMUTABLE(inode)))
                return -EPERM;
@@ -5815,9 +5820,10 @@ int ext4_mark_iloc_dirty(handle_t *handle,
 {
        int err = 0;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb))) {
+       err = ext4_emergency_state(inode->i_sb);
+       if (unlikely(err)) {
                put_bh(iloc->bh);
-               return -EIO;
+               return err;
        }
        ext4_fc_track_inode(handle, inode);
 
@@ -5841,8 +5847,9 @@ ext4_reserve_inode_write(handle_t *handle, struct inode *inode,
 {
        int err;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
-               return -EIO;
+       err = ext4_emergency_state(inode->i_sb);
+       if (unlikely(err))
+               return err;
 
        err = ext4_get_inode_loc(inode, iloc);
        if (!err) {
index b25a27c8669692f5b62012b84715a7b320527743..a67c52063a422460b509795230d238e800a0fae9 100644 (file)
@@ -5653,7 +5653,7 @@ static inline void ext4_mb_show_pa(struct super_block *sb)
 {
        ext4_group_t i, ngroups;
 
-       if (ext4_forced_shutdown(sb))
+       if (ext4_emergency_state(sb))
                return;
 
        ngroups = ext4_get_groups_count(sb);
@@ -5687,7 +5687,7 @@ static void ext4_mb_show_ac(struct ext4_allocation_context *ac)
 {
        struct super_block *sb = ac->ac_sb;
 
-       if (ext4_forced_shutdown(sb))
+       if (ext4_emergency_state(sb))
                return;
 
        mb_debug(sb, "Can't allocate:"
index d64c04ed061ae9ab65f8878ec71ef189e683f53c..af6b3b746fe51f5faf0e890775bb3f9cec6ad72f 100644 (file)
@@ -162,7 +162,7 @@ static int kmmpd(void *data)
        memcpy(mmp->mmp_nodename, init_utsname()->nodename,
               sizeof(mmp->mmp_nodename));
 
-       while (!kthread_should_stop() && !ext4_forced_shutdown(sb)) {
+       while (!kthread_should_stop() && !ext4_emergency_state(sb)) {
                if (!ext4_has_feature_mmp(sb)) {
                        ext4_warning(sb, "kmmpd being stopped since MMP feature"
                                     " has been disabled.");
index 820e7ab7f3a3dd4e01a317d85d3773cb6aa702c2..7ae24530a4aed0615916216584c27f2a57f2b710 100644 (file)
@@ -3157,8 +3157,9 @@ static int ext4_rmdir(struct inode *dir, struct dentry *dentry)
        struct ext4_dir_entry_2 *de;
        handle_t *handle = NULL;
 
-       if (unlikely(ext4_forced_shutdown(dir->i_sb)))
-               return -EIO;
+       retval = ext4_emergency_state(dir->i_sb);
+       if (unlikely(retval))
+               return retval;
 
        /* Initialize quotas before so that eventual writes go in
         * separate transaction */
@@ -3315,8 +3316,9 @@ static int ext4_unlink(struct inode *dir, struct dentry *dentry)
 {
        int retval;
 
-       if (unlikely(ext4_forced_shutdown(dir->i_sb)))
-               return -EIO;
+       retval = ext4_emergency_state(dir->i_sb);
+       if (unlikely(retval))
+               return retval;
 
        trace_ext4_unlink_enter(dir, dentry);
        /*
@@ -3382,8 +3384,9 @@ static int ext4_symlink(struct mnt_idmap *idmap, struct inode *dir,
        struct fscrypt_str disk_link;
        int retries = 0;
 
-       if (unlikely(ext4_forced_shutdown(dir->i_sb)))
-               return -EIO;
+       err = ext4_emergency_state(dir->i_sb);
+       if (unlikely(err))
+               return err;
 
        err = fscrypt_prepare_symlink(dir, symname, len, dir->i_sb->s_blocksize,
                                      &disk_link);
@@ -4205,8 +4208,9 @@ static int ext4_rename2(struct mnt_idmap *idmap,
 {
        int err;
 
-       if (unlikely(ext4_forced_shutdown(old_dir->i_sb)))
-               return -EIO;
+       err = ext4_emergency_state(old_dir->i_sb);
+       if (unlikely(err))
+               return err;
 
        if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
                return -EINVAL;
index 31d8963a3fd6921d35959083b89cebad9ebd00cd..24829b71e05ebd9dc638e5612770908d4ffb5077 100644 (file)
@@ -198,7 +198,7 @@ static int ext4_end_io_end(ext4_io_end_t *io_end)
        } else {
                ret = ext4_convert_unwritten_io_end_vec(handle, io_end);
        }
-       if (ret < 0 && !ext4_forced_shutdown(sb) &&
+       if (ret < 0 && !ext4_emergency_state(sb) &&
            io_end->flag & EXT4_IO_END_UNWRITTEN) {
                ext4_msg(sb, KERN_EMERG,
                         "failed to convert unwritten extents to written "
index 46572529c68b088dcb5ec3bc236b7b5d25e3fd9b..c436da50f31d64a68dd58d8d05d1dbd55e91febc 100644 (file)
@@ -804,7 +804,7 @@ void __ext4_error(struct super_block *sb, const char *function,
        struct va_format vaf;
        va_list args;
 
-       if (unlikely(ext4_forced_shutdown(sb)))
+       if (unlikely(ext4_emergency_state(sb)))
                return;
 
        trace_ext4_error(sb, function, line);
@@ -829,7 +829,7 @@ void __ext4_error_inode(struct inode *inode, const char *function,
        va_list args;
        struct va_format vaf;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
+       if (unlikely(ext4_emergency_state(inode->i_sb)))
                return;
 
        trace_ext4_error(inode->i_sb, function, line);
@@ -864,7 +864,7 @@ void __ext4_error_file(struct file *file, const char *function,
        struct inode *inode = file_inode(file);
        char pathname[80], *path;
 
-       if (unlikely(ext4_forced_shutdown(inode->i_sb)))
+       if (unlikely(ext4_emergency_state(inode->i_sb)))
                return;
 
        trace_ext4_error(inode->i_sb, function, line);
@@ -944,7 +944,7 @@ void __ext4_std_error(struct super_block *sb, const char *function,
        char nbuf[16];
        const char *errstr;
 
-       if (unlikely(ext4_forced_shutdown(sb)))
+       if (unlikely(ext4_emergency_state(sb)))
                return;
 
        /* Special case: if the error is EROFS, and we're not already
@@ -1038,7 +1038,7 @@ __acquires(bitlock)
        struct va_format vaf;
        va_list args;
 
-       if (unlikely(ext4_forced_shutdown(sb)))
+       if (unlikely(ext4_emergency_state(sb)))
                return;
 
        trace_ext4_error(sb, function, line);
@@ -6328,8 +6328,9 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
        bool needs_barrier = false;
        struct ext4_sb_info *sbi = EXT4_SB(sb);
 
-       if (unlikely(ext4_forced_shutdown(sb)))
-               return -EIO;
+       ret = ext4_emergency_state(sb);
+       if (unlikely(ret))
+               return ret;
 
        trace_ext4_sync_fs(sb, wait);
        flush_workqueue(sbi->rsv_conversion_wq);
@@ -6411,7 +6412,7 @@ out:
  */
 static int ext4_unfreeze(struct super_block *sb)
 {
-       if (ext4_forced_shutdown(sb))
+       if (ext4_emergency_state(sb))
                return 0;
 
        if (EXT4_SB(sb)->s_journal) {
@@ -6567,7 +6568,7 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
        flush_work(&sbi->s_sb_upd_work);
 
        if ((bool)(fc->sb_flags & SB_RDONLY) != sb_rdonly(sb)) {
-               if (ext4_forced_shutdown(sb)) {
+               if (ext4_emergency_state(sb)) {
                        err = -EROFS;
                        goto restore_opts;
                }