diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index f38fec3167fb..c4e44e3d58cc 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -1647,6 +1647,7 @@ struct ext4_sb_info { /* Journaling */ struct journal_s *s_journal; unsigned long s_ext4_flags; /* Ext4 superblock flags */ + struct mutex s_shutdown_lock; /* Serializes DEFAULT shutdown requests */ struct mutex s_orphan_lock; /* Protects on disk list changes */ struct list_head s_orphan; /* List of orphaned inodes in on disk list */ diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index e8e579498c99..3019b16320a0 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -818,16 +818,28 @@ int ext4_force_shutdown(struct super_block *sb, u32 flags) if (ext4_forced_shutdown(sb)) return 0; + if (flags == EXT4_GOING_FLAGS_DEFAULT) { + if (mutex_lock_killable(&sbi->s_shutdown_lock)) + return -EINTR; + if (ext4_forced_shutdown(sb)) { + mutex_unlock(&sbi->s_shutdown_lock); + return 0; + } + } + ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags); trace_ext4_shutdown(sb, flags); switch (flags) { case EXT4_GOING_FLAGS_DEFAULT: ret = bdev_freeze(sb->s_bdev); - if (ret) + if (ret) { + mutex_unlock(&sbi->s_shutdown_lock); return ret; + } set_bit(EXT4_FLAGS_SHUTDOWN, &sbi->s_ext4_flags); bdev_thaw(sb->s_bdev); + mutex_unlock(&sbi->s_shutdown_lock); break; case EXT4_GOING_FLAGS_LOGFLUSH: /* diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 9cae52471dee..a1d4fc5c0a68 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -5547,6 +5547,7 @@ static int __ext4_fill_super(struct fs_context *fc, struct super_block *sb) INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ mutex_init(&sbi->s_orphan_lock); + mutex_init(&sbi->s_shutdown_lock); spin_lock_init(&sbi->s_bdev_wb_lock);