From nobody Tue Sep 29 05:34:07 2026 Received: from mail-pl1-f173.google.com (mail-pl1-f173.google.com [209.85.214.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A2FD53921DD for ; Wed, 12 Aug 2026 04:44:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786509843; cv=none; b=pSw3tRqorVYazHnF/LNPUtx4EY1OXzkT130elOP3IdPGo8HxEEDQO1EufKNN5f0TEj/TUh0L4sYr/ATgPzOTSZ526fw7QA9/jhpmKpDLsCNLDyBQXJgscpNPPaQmvuVMxtfdDBNkjoiv11TKBz6bzaNYXYXKVrrDRhg/n58RKrQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786509843; c=relaxed/simple; bh=Geen8rRi9DYSEeIAFJv4tuQyYu6xQCEWIEOmRHPkpYE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=DmDAl9+6sAXkf5nm3RT8CxTd+lI2Sg3hXWwN0vjCMH3/olERX90uX4b+n9tNGaDvwyITYtluohH5OmcMCd1oE44MF9yvVa4zUdkoRj+pSHJxN0iHJveQSe4xo095X1h4RAu4/0sufrxDphpYBtYnwF7nYacjZ9lW5WaODSyZIME= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=LLuQZnzA; arc=none smtp.client-ip=209.85.214.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="LLuQZnzA" Received: by mail-pl1-f173.google.com with SMTP id d9443c01a7336-2cace91f112so7746065ad.0 for ; Tue, 11 Aug 2026 21:44:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1786509841; x=1787114641; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to:content-type; bh=Z09gGCJzZ8Oqr2QOAqOOmcBjVqdoajQ3RwQNJtoTNM0=; b=LLuQZnzA411Sgd9r+cj7XCqdwMkDlYLSyzE+jQNhBxP1UTzkwU9MixzM6oUWzBGK3X Q4ShdAAoK1sQwtulXo+FZb6fRO0klCvhGRN8AprBTEJ+n3yR3bhCdzlO+ZZkpaW5QdKJ xqTWJhkfqVDXvujUOtz4ckSMvjSRRWc53BKhA8QwYlsdgUiP43hNDkSkP5qBKVUkx7YX vJj/edmDHYoTkAGZndC2UwBsBduD7Zp4f8CsZMHAoL18NUTMHsemFA21nzUTPpOpQWUZ i13tawS4JPLkHd9dg0HbTI7SyhFoDKzo5zVZJfzJn/eWCGJn2Fq40kG9HWKo4so6XbVd HCig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786509841; x=1787114641; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Z09gGCJzZ8Oqr2QOAqOOmcBjVqdoajQ3RwQNJtoTNM0=; b=iZO3kEkfNgvyCO4EBZYbccwy9YDFwpIByki5eAHBk742n9WhNq/xBTEskeGCd8KV7N /sBZRva2cece+Nas1HVUqJvEgv3vyEttPYAZJMa0ZbB0e+YkoNNzp9zcM1qsyGXcKNHr zVySHCyPPvzMseZ9TgqP2YIHA2hmhdbgxrIVMNXC1WhYfdbZ2AuKAIF6wBZZUXRnIhRm 4J0/T5SCmtwlKiE8jEKd/IAf3ADkaOgzMvjLwRy1Lyi0ouaMyaSzNHqjWre5ZCSkYkcO p/kmBjNxvXBWtV86H4DPbazODwDF7S56uiLKd95K9KiQksgH8AxNr6Q5KfxAS8ZunIMG QeLA== X-Forwarded-Encrypted: i=1; AHgh+Rpn81avGvTZFxtsovrUwaEY790Scjds8pMxd4xY/r4vC3+ZRZquyOymU4A0tbEsUdHRl0rhjFnG/UqFuig=@vger.kernel.org X-Gm-Message-State: AOJu0Yx2vXG2x3boTpQGS6VHpSRL9eKLA75kmLHr5oEv03384Lt0T2lh j1Ldvg9J1ajG0Yiuuk1mSrrIaYQ4N4MYock0V9iss+qs918cHa8cvpje X-Gm-Gg: AR+sD13bcQPtSOQOHKLvYQORYVnCQKkHkSkoH+NrVSfS/ldFG1t0zrOGO8TJb8l75k9 SfB170N+lrvp5WZg7CwK9w2MPoIAcJccq7t0QL/8JWqcqWkOeAkAZNR7FoI3/r3C6G0CDgH10Lf PYtECASMJ9TGjV2xCD2nsMQKDRpD+flVzIRnXXxfQJkJUd4hDK7sJcnWDuEZm9p1G6Yf7RgA91K K2XldV7IpJQGK+kw6TVAJDEczl4nWepL29oVXVLN9l1EJzfQo34hLIhV849kzLFGhr76loov0DT n1n5eVlYU1ESMjx7W3bV1vu1cSl++8k/p0DAl28EKm29zM4GFoM+lX/xFEQ6FQhCfVww0+U0U8L xExYJuDYN+U8CpTONsvGgsfEbTdxCM6knsyG0eSXEyV4MsIsiSoLNue6pFAggvu56zpIygjY1LR UsZ6Qq9O4MS4rJwHkqGX2nlmtbtwXu+7ER3N/WPfGz/27cfPx314BCv1/px2GBr21ebe25XP+Mj 9VlJCwClbipmcY2S84= X-Received: by 2002:a17:903:230b:b0:2ca:d975:5bbd with SMTP id d9443c01a7336-2d3455ffabcmr25703105ad.20.1786509840697; Tue, 11 Aug 2026 21:44:00 -0700 (PDT) Received: from jubuntu-dev.. (211-23-39-77.hinet-ip.hinet.net. [211.23.39.77]) by smtp.gmail.com with ESMTPSA id d9443c01a7336-2d350fb0cd0sm1177695ad.4.2026.08.11.21.43.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 11 Aug 2026 21:44:00 -0700 (PDT) From: Hsiu-Hsien Lee To: tytso@mit.edu Cc: adilger.kernel@dilger.ca, jack@suse.cz, libaokun@linux.alibaba.com, ojaswin@linux.ibm.com, ritesh.list@gmail.com, yi.zhang@huawei.com, harshadshirwadkar@gmail.com, linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org, Hsiu-Hsien Lee , stable@vger.kernel.org Subject: [PATCH] ext4: fix fast commit replay failing on a read-only mount Date: Wed, 12 Aug 2026 12:43:53 +0800 Message-ID: <20260812044353.1018268-1-swinds24@gmail.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A filesystem with fast_commit that needs recovery cannot be mounted read-only: EXT4-fs (dm-0): INFO: recovery required on readonly filesystem EXT4-fs (dm-0): write access will be enabled during recovery WARNING: CPU: 22 PID: 5544 at fs/ext4/ext4_jbd2.c:73 ext4_journal_check_start __ext4_journal_start_sb __ext4_unlink ext4_fc_replay do_one_pass jbd2_journal_recover jbd2_journal_load __ext4_fill_super JBD2: journal recovery failed EXT4-fs (dm-0): error loading journal Fast commit replay runs ext4 metadata operations instead of writing blocks through the buffer cache: ext4_fc_replay_{unlink,link,create}() reach __ext4_unlink() and __ext4_link(), which start a handle. ext4_journal_check_start() returns -EROFS on a read-only sb, and as that is not -ENOENT it propagates out of jbd2_journal_recover() and kills the whole recovery. The EXT4_FC_REPLAY check that would hand out a no-journal handle sits after the sb_rdonly() test, so replay can never complete read-only. ext4_load_journal() has already promised that write access will be enabled during recovery, so make that true for the superblock as well: clear SB_RDONLY across jbd2_journal_load() when recovery is needed on a read-only mount and the devices are writable, as ext4_orphan_cleanup() does. Unlike ext4_handle_error(), which avoids SB_RDONLY because it would need s_umount, the sb here is still inside ext4_fill_super() and not published, so nothing can observe it. The failure is not clean either: the replay handlers passing a NULL handle (ext4_fc_replay_inode(), _add_range(), _del_range()) never hit ext4_journal_check_start() and do write, leaving a partially applied fast commit behind. Reproducer, where the unlink only ever reaches the fast commit area: mke2fs -q -F -t ext4 -O fast_commit -b 4096 /dev/sdb3 262144 mount /dev/sdb3 /mnt dd if=3D/dev/zero of=3D/mnt/victim bs=3D4k count=3D1 conv=3Dfsync sync # victim now in a full commit rm /mnt/victim dd if=3D/dev/zero of=3D/mnt/trigger bs=3D4k count=3D1 conv=3Dfsync mount -o ro /dev/sdb3 /mnt Without this patch that mount fails; with it recovery completes and victim is gone, i.e. the UNLINK record was really replayed. Fixes: 8016e29f4362 ("ext4: fast commit recovery path") Cc: stable@vger.kernel.org Signed-off-by: Hsiu-Hsien Lee Reviewed-by: Jan Kara --- fs/ext4/super.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 245f67d10ded..6c2b275a9cf3 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -6096,6 +6096,7 @@ static int ext4_load_journal(struct super_block *sb, int err =3D 0; int really_read_only; int journal_dev_ro; + bool enable_write =3D false; =20 if (WARN_ON_ONCE(!ext4_has_feature_journal(sb))) return -EFSCORRUPTED; @@ -6152,6 +6153,7 @@ static int ext4_load_journal(struct super_block *sb, } ext4_msg(sb, KERN_INFO, "write access will " "be enabled during recovery"); + enable_write =3D true; } } =20 @@ -6168,7 +6170,19 @@ static int ext4_load_journal(struct super_block *sb, if (save) memcpy(save, ((char *) es) + EXT4_S_ERR_START, EXT4_S_ERR_LEN); + /* + * Fast commit replay performs regular ext4 metadata updates + * (see ext4_fc_replay()) which refuse to run on a read-only + * superblock. We promised write access above, so make that + * true for the duration of the recovery, the same way + * ext4_orphan_cleanup() does. The superblock is not published + * yet, so nothing can observe the transient state. + */ + if (enable_write) + sb->s_flags &=3D ~SB_RDONLY; err =3D jbd2_journal_load(journal); + if (enable_write) + sb->s_flags |=3D SB_RDONLY; if (save && memcmp(((char *) es) + EXT4_S_ERR_START, save, EXT4_S_ERR_LEN)) { memcpy(((char *) es) + EXT4_S_ERR_START, --=20 2.43.0