From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 18594606A32F for ; Thu, 29 Oct 2026 16:07:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key, unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=bombadil.20210309 header.b=RQC87GZ/; dkim=fail reason="signature verification failed" (2048-bit key, unprotected) header.d=kernel.org header.i=@kernel.org header.a=rsa-sha256 header.s=k20260515 header.b=AlRagrjY DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References:Message-Id :MIME-Version:Subject:Date:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Unsubscribe-Post:List-Owner; bh=OAHEgVdahfBob0BeT0dXJNKwESgzQtymedMwoCE41m0=; b=RQC87GZ/rMxi3GOISeqUqcB7bk npkDv2QGKNfDg2IQXKowGahP1JyzWIA1lXaATyNLUcxumOwJbKw1wH7wu1REEoEO7ZBJb4lc10aKx pCqrjwPKMBt3h7hvqDGCGFszWkYuJkvPWx+Xh6wN1JjrTwQ2pg6IxT9yR3aqchve+9FJIQxpQHhvP l8z+I1RCXiA5jEuMg6uOS9hzsxENSxekpILzLu611V3G4jqt4qaYaovzf6b9TXVFvySLsrmHrykLC 178DC8uxrkYFEvCwX1Yuv/a8YuikW24ixy1Km4h5PZAakSA2mTdUtldTbmgimkYA97OU2Ig5Wlxfs nVSdonEQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.100.1 #2 (Red Hat Linux)) id 1xMSfD-00000009jwO-3NxP; Thu, 29 Oct 2026 16:07:39 +0000 Received: from sea.source.kernel.org ([172.234.252.31]) by bombadil.infradead.org with esmtps (Exim 4.100.1 #2 (Red Hat Linux)) id 1xMSfC-00000009jvA-2dUZ for linux-mtd@lists.infradead.org; Thu, 29 Oct 2026 16:07:38 +0000 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by sea.source.kernel.org (Postfix) with ESMTP id 6358840A75; Thu, 29 Oct 2026 16:07:38 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 805901F01826; Thu, 29 Oct 2026 16:07:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1793290058; bh=xNgZk8sqL0pi/BgMC10+2IZal4rVk0LbmvrvuXhJ2Dk=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=AlRagrjY6o1gWRJCJgnfCv2vf7Bcfac+CV9YW1vTP2WwuW9tEuQHBhevP5ePYv6wU tZm/UfOxlRJO5sw/a2Nplq+A8PWYDB8BkatYa8/unWums0YZOd7jiODkUS1bQuoXDc 2r237CVoc0X/eY5Af46WpEvX1ZVjahYsPaB2Gk6AXIVz2nlCClJI5khPlYaE7iT7p/ XDhxiJCpt5DJKGR+EHHl4F0uT78HBaolBZCT7M33rjZhbbhgAo2PcjBtaKm9eZkw6X NWXJ/Hi6PIE9ox1qUK/7i9IAhFrGTWMyjol5owtz516sIM6RN//r2rt7z0U4U/YYMu YskLTlKankV9Q== From: Christian Brauner Date: Thu, 29 Oct 2026 17:06:55 +0100 Subject: [PATCH v2 04/34] ext2: don't set SB_RDONLY after filesystem errors X-Archived-By: MIME-Version: 1.0 Message-Id: <20261029-work-fs-sb_rdonly-v2-4-2f44f64f0b66@kernel.org> References: <20261029-work-fs-sb_rdonly-v2-0-2f44f64f0b66@kernel.org> In-Reply-To: <20261029-work-fs-sb_rdonly-v2-0-2f44f64f0b66@kernel.org> To: linux-fsdevel@vger.kernel.org, Jan Kara Cc: Al Viro , 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)" , Karl Mehltretter X-Mailer: b4 0.17-dev-ce4c1 X-Developer-Signature: v=1; a=openpgp-sha256; l=7123; i=brauner@kernel.org; h=from:subject:message-id; bh=5u6R9zyuZJuhy+aULhR8Qmnz6ME9R6gfqmURw2sS7bQ=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWQ9ztdTcqkry2sNm/UkdlqstlmLZfOJPyXf/Zv1Gi4ds vu446ZZRykLgxgXg6yYIotDu0m43HKeis1GmRowc1iZQIYwcHEKwETmbWBk6NSRkMm8L+79MOZB ilh2q/3C3Y21/O3N07TCL2Uniy54yPA/osBzTguz6qL/+QvZjD99OlhX/nB9ZZQO+13e3VnnFGa wAQA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "linux-mtd" X-Spam-Status: No, score=-16.9 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_EF,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE, SPF_PASS,USER_AGENT_GIT autolearn=ham autolearn_force=no version=4.0.1 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on aws-us-west-2-korg-listserv-alma10-1 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 Link: https://lore.kernel.org/r/20260903060855.4610-1-kmehltretter@gmail.com Signed-off-by: Christian Brauner (Amutable) --- 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 ______________________________________________________ Linux MTD discussion mailing list http://lists.infradead.org/mailman/listinfo/linux-mtd/