Set SB_STATE_EMERGENCY_RO next to EXT4_FLAGS_EMERGENCY_RO when an error makes the filesystem read-only. The VFS then refuses modifications before they reach ext4 and reports the superblock as read-only like it did when ext4 still set SB_RDONLY. The shutdown state stays ext4's own and so do all of ext4's checks because they cover both states. ext4 keeps showing "emergency_ro" in its mount options. EXT4_IOC_SHUTDOWN with EXT4_GOING_FLAGS_DEFAULT fails after an error on mainline today because ext4_sync_fs() fails the freeze. freeze_super() refuses it in the emergency state now. ext4 refuses writes in that state anyway and the journal is aborted, so shut down without the freeze like EXT4_GOING_FLAGS_NOLOGFLUSH does. Reviewed-by: Jan Kara Signed-off-by: Christian Brauner (Amutable) --- fs/ext4/ioctl.c | 4 ++++ fs/ext4/super.c | 1 + 2 files changed, 5 insertions(+) diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index e8e579498c990..ce0e0ebdded61 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -821,6 +821,10 @@ int ext4_force_shutdown(struct super_block *sb, u32 flags) ext4_msg(sb, KERN_ALERT, "shut down requested (%d)", flags); trace_ext4_shutdown(sb, flags); + /* After an error there is nothing to flush and freezing fails. */ + if (flags == EXT4_GOING_FLAGS_DEFAULT && ext4_emergency_ro(sb)) + flags = EXT4_GOING_FLAGS_NOLOGFLUSH; + switch (flags) { case EXT4_GOING_FLAGS_DEFAULT: ret = bdev_freeze(sb->s_bdev); diff --git a/fs/ext4/super.c b/fs/ext4/super.c index ae5ba6823c01c..afbdbb607b144 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -757,6 +757,7 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error, * and other problems. */ set_bit(EXT4_FLAGS_EMERGENCY_RO, &EXT4_SB(sb)->s_ext4_flags); + sb_set_emergency_ro(sb); } static void update_super_work(struct work_struct *work) -- 2.53.0