From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org, Jan Kara <jack@suse.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>,
ecryptfs@vger.kernel.org, linux-ext4@vger.kernel.org,
jfs-discussion@lists.sourceforge.net,
linux-nilfs@vger.kernel.org, exfat@lists.linux.dev,
linux-mm@kvack.org, ntfs@lists.linux.dev,
ocfs2-devel@lists.linux.dev, linux-btrfs@vger.kernel.org,
gfs2@lists.linux.dev, linux-efi@vger.kernel.org,
linux-mtd@lists.infradead.org, linux-xfs@vger.kernel.org,
"Christian Brauner (Amutable)" <brauner@kernel.org>,
Karl Mehltretter <kmehltretter@gmail.com>
Subject: [PATCH v2 04/34] ext2: don't set SB_RDONLY after filesystem errors
Date: Thu, 29 Oct 2026 17:06:55 +0100 [thread overview]
Message-ID: <20261029-work-fs-sb_rdonly-v2-4-2f44f64f0b66@kernel.org> (raw)
In-Reply-To: <20261029-work-fs-sb_rdonly-v2-0-2f44f64f0b66@kernel.org>
With errors=remount-ro ext2_error() sets SB_RDONLY from whatever context
hit the error and without holding s_umount. That races with everyone
else changing sb->s_flags and it breaks freezing. If it happens while
the filesystem is frozen thaw_super() sees a read-only superblock and
leaves the s_writers rwsems locked so every writer hangs. A lookup in a
corrupted directory is enough. Karl proposed teaching thaw_super() about
it but Jan preferred fixing the filesystems (cf. [1]) like ext4 and f2fs
already did.
So call sb_set_emergency_ro() instead and let the VFS refuse
modifications. ext2 still refuses allocations, ext2_write_inode(),
ext2_sync_fs() and ext2_xattr_set() itself. The superblock isn't written
after the error is recorded and unlinked inodes are left to e2fsck.
ext2_handle_dirsync() treats EROFS as success in that state because the
entry was already changed.
A remount to read-write fails until umount and writes through file
descriptors opened before the error fail with EROFS.
[1]: https://lore.kernel.org/r/hyhuckyohsabx2suvq3z7uy3pbgmihva6wgzxr3op7pzcrlu33@p7zzlgp2ehjf
Reported-by: Karl Mehltretter <kmehltretter@gmail.com>
Link: https://lore.kernel.org/r/20260903060855.4610-1-kmehltretter@gmail.com
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
fs/ext2/balloc.c | 5 +++++
fs/ext2/dir.c | 3 +++
fs/ext2/ialloc.c | 2 ++
fs/ext2/inode.c | 10 ++++++++--
fs/ext2/super.c | 24 ++++++++++++++++++------
fs/ext2/xattr.c | 2 ++
6 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c
index 80acc1e19387..77f2ed5a76a2 100644
--- a/fs/ext2/balloc.c
+++ b/fs/ext2/balloc.c
@@ -1236,6 +1236,11 @@ ext2_fsblk_t ext2_new_blocks(struct inode *inode, ext2_fsblk_t goal,
*errp = -ENOSPC;
sb = inode->i_sb;
+ if (sb_emergency_ro(sb)) {
+ *errp = -EROFS;
+ return 0;
+ }
+
/*
* Check quota for allocation of this block.
*/
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index e17bbc7598c1..c2c9fc2d0b27 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -445,6 +445,9 @@ static int ext2_handle_dirsync(struct inode *dir)
err = filemap_write_and_wait(dir->i_mapping);
if (!err)
err = sync_inode_metadata(dir, 1);
+ /* The change is done, an error made us read-only in the meantime. */
+ if (err == -EROFS && sb_emergency_ro(dir->i_sb))
+ err = 0;
return err;
}
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index bf21b57cf98c..2741ecd2b94f 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -433,6 +433,8 @@ struct inode *ext2_new_inode(struct inode *dir, umode_t mode,
int err;
sb = dir->i_sb;
+ if (sb_emergency_ro(sb))
+ return ERR_PTR(-EROFS);
inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index 12ac4cfe1500..5c4831f8f45d 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -71,7 +71,9 @@ void ext2_evict_inode(struct inode * inode)
struct ext2_block_alloc_info *rsv;
int want_delete = 0;
- if (!inode->i_nlink && !is_bad_inode(inode)) {
+ /* After an error made us read-only the inode is left to e2fsck. */
+ if (!inode->i_nlink && !is_bad_inode(inode) &&
+ !sb_emergency_ro(inode->i_sb)) {
want_delete = 1;
dquot_initialize(inode);
} else {
@@ -1481,10 +1483,14 @@ int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
uid_t uid = i_uid_read(inode);
gid_t gid = i_gid_read(inode);
struct buffer_head * bh;
- struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
+ struct ext2_inode *raw_inode;
int n;
int err = 0;
+ if (sb_emergency_ro(sb))
+ return -EROFS;
+
+ raw_inode = ext2_get_inode(sb, ino, &bh);
if (IS_ERR(raw_inode))
return -EIO;
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index fb217ef2d69f..804a7224066d 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -53,7 +53,7 @@ void ext2_error(struct super_block *sb, const char *function,
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = sbi->s_es;
- if (!sb_rdonly(sb)) {
+ if (!sb_rdonly(sb) && !sb_emergency_ro(sb)) {
spin_lock(&sbi->s_lock);
sbi->s_mount_state |= EXT2_ERROR_FS;
es->s_state |= cpu_to_le16(EXT2_ERROR_FS);
@@ -73,11 +73,11 @@ void ext2_error(struct super_block *sb, const char *function,
if (test_opt(sb, ERRORS_PANIC))
panic("EXT2-fs: panic from previous error\n");
- if (!sb_rdonly(sb) && test_opt(sb, ERRORS_RO)) {
+ /* SB_RDONLY needs s_umount, see sb_set_emergency_ro(). */
+ if (!sb_rdonly(sb) && test_opt(sb, ERRORS_RO) &&
+ sb_set_emergency_ro(sb))
ext2_msg(sb, KERN_CRIT,
"error: remounting filesystem read-only");
- sb->s_flags |= SB_RDONLY;
- }
}
static void ext2_msg_fc(struct fs_context *fc, const char *prefix,
@@ -179,7 +179,7 @@ static void ext2_put_super (struct super_block * sb)
ext2_xattr_destroy_cache(sbi->s_ea_block_cache);
sbi->s_ea_block_cache = NULL;
- if (!sb_rdonly(sb)) {
+ if (!sb_rdonly(sb) && !sb_emergency_ro(sb)) {
struct ext2_super_block *es = sbi->s_es;
spin_lock(&sbi->s_lock);
@@ -1287,6 +1287,10 @@ static int ext2_sync_fs(struct super_block *sb, int wait)
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = EXT2_SB(sb)->s_es;
+ /* Nothing may be written after an error made us read-only. */
+ if (sb_emergency_ro(sb))
+ return 0;
+
/*
* Write quota structures to quota file, sync_blockdev() will write
* them to disk later
@@ -1307,6 +1311,9 @@ static int ext2_freeze(struct super_block *sb)
{
struct ext2_sb_info *sbi = EXT2_SB(sb);
+ if (sb_emergency_ro(sb))
+ return 0;
+
/*
* Open but unlinked files present? Keep EXT2_VALID_FS flag cleared
* because we have unattached inodes and thus filesystem is not fully
@@ -1349,7 +1356,9 @@ static int ext2_reconfigure(struct fs_context *fc)
int flags = fc->sb_flags;
int err;
- sync_filesystem(sb);
+ /* Nothing may be written after an error made us read-only. */
+ if (!sb_emergency_ro(sb))
+ sync_filesystem(sb);
new_opts.s_mount_opt = ctx->vals_s_mount_opt;
new_opts.s_resuid = ctx->s_resuid;
@@ -1360,6 +1369,9 @@ static int ext2_reconfigure(struct fs_context *fc)
if ((bool)(flags & SB_RDONLY) == sb_rdonly(sb))
goto out_set;
if (flags & SB_RDONLY) {
+ /* After an error nothing may be written, just go read-only. */
+ if (sb_emergency_ro(sb))
+ goto out_set;
if (le16_to_cpu(es->s_state) & EXT2_VALID_FS ||
!(sbi->s_mount_state & EXT2_VALID_FS))
goto out_set;
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c
index 8f608930a48c..12dfffff189c 100644
--- a/fs/ext2/xattr.c
+++ b/fs/ext2/xattr.c
@@ -429,6 +429,8 @@ ext2_xattr_set(struct inode *inode, int name_index, const char *name,
ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld",
name_index, name, value, (long)value_len);
+ if (sb_emergency_ro(sb))
+ return -EROFS;
if (value == NULL)
value_len = 0;
if (name == NULL)
--
2.53.0
next prev parent reply other threads:[~2026-10-29 16:07 UTC|newest]
Thread overview: 49+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-29 16:06 [PATCH v2 00/34] fs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:06 ` [PATCH v2 01/34] ecryptfs: don't leak the inode when a lookup can't open the lower file Christian Brauner
2026-10-29 16:06 ` [PATCH v2 02/34] ecryptfs: fall back to a read-only " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 03/34] fs: add a generic emergency read-only state Christian Brauner
2026-10-29 16:06 ` Christian Brauner [this message]
2026-10-29 16:06 ` [PATCH v2 05/34] jfs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 06/34] nilfs2: " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 07/34] fat: " Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 08/34] exfat: keep the current mount options on remount Christian Brauner
2026-10-29 16:07 ` [PATCH v2 09/34] exfat: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 10/34] exfat: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 11/34] hfs: don't set SB_RDONLY after MDB write errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 12/34] hfs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 13/34] hfsplus: don't set SB_RDONLY when creating the attributes tree Christian Brauner
2026-10-29 16:07 ` [PATCH v2 14/34] affs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 15/34] ufs: " Christian Brauner
2026-10-29 16:07 ` [PATCH v2 16/34] hpfs: " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 17/34] ntfs: " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 18/34] ntfs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 19/34] ocfs2: keep the current mount options on remount Christian Brauner
2026-10-30 2:58 ` Joseph Qi
2026-10-29 16:07 ` [PATCH v2 20/34] ocfs2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 3:01 ` Joseph Qi
2026-10-29 16:07 ` [PATCH v2 21/34] zonefs: don't set SB_RDONLY after I/O errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 22/34] zonefs: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 23/34] btrfs: check BTRFS_FS_STATE_RO instead of SB_RDONLY at runtime Christian Brauner
2026-10-29 16:07 ` [PATCH v2 24/34] btrfs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-29 16:07 ` [PATCH v2 25/34] gfs2: wait for a pending withdraw before remounting read-only Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 26/34] gfs2: don't set SB_RDONLY on withdraw Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 27/34] efivarfs: stop using SB_RDONLY for read-only efivar ops Christian Brauner
2026-10-29 16:07 ` [PATCH v2 28/34] ubifs: don't set SB_RDONLY after errors Christian Brauner
2026-10-30 3:42 ` Zhihao Cheng
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 29/34] selftests/filesystems: test filesystem errors while frozen Christian Brauner
2026-10-29 16:07 ` [PATCH v2 30/34] ext4: allow remounting read-only in the emergency state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 31/34] ext4: use the generic emergency read-only state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 32/34] selftests/filesystems: test ext4 remounts in the emergency state Christian Brauner
2026-10-29 16:07 ` [PATCH v2 33/34] xfs: allow remounting read-only after a shutdown Christian Brauner
2026-10-29 16:07 ` [PATCH v2 34/34] selftests/filesystems: test xfs remounts " Christian Brauner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261029-work-fs-sb_rdonly-v2-4-2f44f64f0b66@kernel.org \
--to=brauner@kernel.org \
--cc=ecryptfs@vger.kernel.org \
--cc=exfat@lists.linux.dev \
--cc=gfs2@lists.linux.dev \
--cc=jack@suse.com \
--cc=jfs-discussion@lists.sourceforge.net \
--cc=kmehltretter@gmail.com \
--cc=linux-btrfs@vger.kernel.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-mtd@lists.infradead.org \
--cc=linux-nilfs@vger.kernel.org \
--cc=linux-xfs@vger.kernel.org \
--cc=ntfs@lists.linux.dev \
--cc=ocfs2-devel@lists.linux.dev \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox