From: sashiko-bot@kernel.org
To: "Christian Brauner" <brauner@kernel.org>, "Jan Kara" <jack@suse.com>
Cc: "Al Viro" <viro@zeniv.linux.org.uk>,
linux-ext4@vger.kernel.org, linux-mm@kvack.org,
linux-efi@vger.kernel.org, linux-mtd@lists.infradead.org,
dsterba@suse.cz, tytso@mit.edu, "Mark Fasheh" <mark@fasheh.com>,
"Joel Becker" <jlbec@evilplan.org>,
"Joseph Qi" <joseph.qi@linux.alibaba.com>
Subject: Re: [PATCH v2 26/34] gfs2: don't set SB_RDONLY on withdraw
Date: Fri, 30 Oct 2026 16:10:10 +0000 [thread overview]
Message-ID: <sashiko-outbox-191245@kernel.org> (raw)
In-Reply-To: <20261029-work-fs-sb_rdonly-v2-26-2f44f64f0b66@kernel.org>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Critical] gfs2: missing withdraw check in gfs2_aspace_writepages() after SB_RDONLY drop
- [High] gfs2: double freeze glock acquisition in gfs2_freeze_super() error path
- [High] gfs2: gfs2_freeze_fs() allows freezing withdrawn fs after journal clear
--
commit 492245d825d0faf64cbdfa5077542cb35552bb3d
Author: Christian Brauner <brauner@kernel.org>
gfs2: don't set SB_RDONLY on withdraw
This commit stops setting SB_RDONLY in do_withdraw() so that thawing and
unmounting a withdrawn filesystem do not leave s_writers rwsems locked due
to a read-only superblock. It updates inode eviction, quota sync, inode
writeback, and freeze/thaw handling to check gfs2_withdrawn() directly.
> diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
> index f61c309368ef1..82f9d90f35788 100644
> --- a/fs/gfs2/super.c
> +++ b/fs/gfs2/super.c
> @@ -455,6 +455,9 @@ static int gfs2_write_inode(struct inode *inode, struct writeback_control *wbc)
> int ret = 0;
> bool flush_all = (wbc->sync_mode == WB_SYNC_ALL || gfs2_is_jdata(ip));
>
> + if (gfs2_withdrawn(sdp))
> + return -EIO;
[Severity: Critical]
Does checking gfs2_withdrawn(sdp) only in gfs2_write_inode() allow dirty
resource group metadata buffers in sdp->sd_inode->i_mapping to be written to
disk after a withdraw now that do_withdraw() no longer sets SB_RDONLY?
Resource group metadata buffers are allocated in gfs2_aspace(sdp)
(sdp->sd_inode->i_mapping), which uses gfs2_rgrp_aops with
gfs2_aspace_writepages() in fs/gfs2/meta_io.c as its .writepages callback:
fs/gfs2/meta_io.c:gfs2_aspace_writepages() {
while ((folio = writeback_iter(mapping, wbc, folio, &error)))
gfs2_aspace_write_folio(folio, wbc);
}
When a transaction modifying resource group blocks commits in gfs2_unpin(),
mark_buffer_dirty(bh) marks the folio dirty in sdp->sd_inode->i_mapping and
sets I_DIRTY_PAGES on sdp->sd_inode. If the filesystem then withdraws,
do_withdraw() drains the AIL via gfs2_ail_drain() without clearing BH_Dirty
or the folio dirty state, and gfs2_withdraw_glocks() -> withdraw_glock() in
fs/gfs2/glock.c calls request_demote() without queueing gl->gl_work, leaving
cached resource group glocks with no active holders undemoted and their
dirty buffers in sdp->sd_inode->i_mapping uninvalidated until
gfs2_put_super().
Previously, setting SB_RDONLY in do_withdraw() caused sync_filesystem() and
sync_inodes_one_sb() to return early. Without SB_RDONLY, sync_filesystem()
during sync, remount-ro in gfs2_reconfigure(), or umount in
generic_shutdown_super() runs:
__writeback_single_inode(sdp->sd_inode, &wbc)
-> do_writepages(sdp->sd_inode->i_mapping, wbc)
-> gfs2_aspace_writepages()
-> gfs2_aspace_write_folio()
which submits writes for those dirty resource group buffers to the block
device without reaching gfs2_write_inode(). Should gfs2_aspace_writepages()
also check gfs2_withdrawn(sdp)?
> @@ -686,7 +689,8 @@ static int gfs2_do_thaw(struct gfs2_sbd *sdp, enum freeze_holder who, const void
> int error;
>
> error = gfs2_freeze_lock_shared(sdp);
> - if (error)
> + /* A withdrawn filesystem can't get the freeze glock back, thaw anyway. */
> + if (error && !gfs2_withdrawn(sdp))
> goto fail;
> error = thaw_super(sb, who, freeze_owner);
> if (!error)
> @@ -751,6 +755,11 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who,
> mutex_unlock(&sdp->sd_freeze_mutex);
> return -EBUSY;
> }
> + /* A withdrawn filesystem can't take the freeze glock anymore. */
> + if (gfs2_withdrawn(sdp)) {
> + mutex_unlock(&sdp->sd_freeze_mutex);
> + return -EIO;
> + }
>
> for (;;) {
[Severity: High]
Can a withdrawn filesystem still be frozen once do_withdraw() clears
SDF_JOURNAL_LIVE?
Without SB_RDONLY set by do_withdraw(), VFS freeze_super() on a withdrawn
filesystem no longer takes the sb_rdonly(sb) shortcut and instead locks the
s_writers rwsems, calls sync_filesystem(sb), and invokes
sb->s_op->freeze_fs(sb), which is gfs2_freeze_fs() in fs/gfs2/super.c:
fs/gfs2/super.c:gfs2_freeze_fs() {
if (test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
gfs2_log_flush(sdp, NULL, GFS2_LOG_HEAD_FLUSH_FREEZE |
GFS2_LFC_FREEZE_GO_SYNC);
if (gfs2_withdrawn(sdp))
return -EIO;
}
return 0;
}
Because do_withdraw() in fs/gfs2/util.c clears SDF_JOURNAL_LIVE,
gfs2_freeze_fs() skips the if-block and returns 0 instead of -EIO.
If a freeze is triggered via freeze_store() in fs/gfs2/sys.c or
gfs2_freeze_func() in fs/gfs2/super.c (which call VFS freeze_super()
directly rather than gfs2_freeze_super()), or if a withdraw completes during
the msleep(1000) retry loop in gfs2_freeze_super() after the initial
gfs2_withdrawn(sdp) check above, won't freeze_super() succeed on the
withdrawn filesystem and leave s_writers locked? Should gfs2_freeze_fs()
check gfs2_withdrawn(sdp) outside the SDF_JOURNAL_LIVE check?
> @@ -767,6 +776,13 @@ static int gfs2_freeze_super(struct super_block *sb, enum freeze_holder who,
> break;
> }
>
> + /* Withdrawn meanwhile, don't take the freeze glock again. */
> + if (gfs2_withdrawn(sdp)) {
> + (void)thaw_super(sb, who, freeze_owner);
> + error = -EIO;
> + goto out;
> + }
> +
> (void)gfs2_do_thaw(sdp, who, freeze_owner);
[Severity: High]
When gfs2_lock_fs_check_clean(sdp) fails in gfs2_freeze_super(), doesn't
calling gfs2_do_thaw() below re-initialize sdp->sd_freeze_gh while it is
already queued and holding sdp->sd_freeze_gl in LM_ST_SHARED mode?
Looking at gfs2_lock_fs_check_clean() in fs/gfs2/super.c, if it fails before
gfs2_freeze_unlock(sdp) it never drops the shared freeze glock, and if it
fails after gfs2_freeze_unlock(sdp) (for example, returning -EBUSY when a
journal is dirty or failing during a concurrent withdraw) it jumps to
relock_shared:
fs/gfs2/super.c:gfs2_lock_fs_check_clean() {
...
gfs2_freeze_unlock(sdp);
relock_shared:
error2 = gfs2_freeze_lock_shared(sdp);
gfs2_assert_withdraw(sdp, !error2);
out:
while (!list_empty(&list)) {
...
return error;
}
When gfs2_lock_fs_check_clean() returns a non-zero error to
gfs2_freeze_super() without the filesystem having withdrawn,
sdp->sd_freeze_gh is already holding sdp->sd_freeze_gl in LM_ST_SHARED mode.
Calling gfs2_do_thaw(sdp, who, freeze_owner) then calls
gfs2_freeze_lock_shared(sdp) -> gfs2_glock_nq_init() a second time on
sdp->sd_freeze_gh:
gfs2_do_thaw()
-> gfs2_freeze_lock_shared()
-> gfs2_glock_nq_init(sdp->sd_freeze_gl, ..., &sdp->sd_freeze_gh)
-> __gfs2_holder_init()
In __gfs2_holder_init() in fs/gfs2/glock.c, INIT_LIST_HEAD(&gh->gh_list)
overwrites sdp->sd_freeze_gh.gh_list while it is still linked on
sdp->sd_freeze_gl->gl_holders, corrupting gl_holders, leaking the glock and
pid references, and triggering the recursive holder check in add_to_queue()
(or if a withdraw races between the gfs2_withdrawn(sdp) check in
gfs2_freeze_super() and gfs2_freeze_lock_shared() in gfs2_do_thaw(),
gfs2_holder_uninit() clears gh_gl = NULL while leaving the corrupted list
entry on gl_holders, and gfs2_do_thaw() now ignores the error).
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261029-work-fs-sb_rdonly-v2-0-2f44f64f0b66@kernel.org?part=26
next prev parent reply other threads:[~2026-10-30 16:10 UTC|newest]
Thread overview: 72+ 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-30 16:09 ` sashiko-bot
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-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 04/34] ext2: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:06 ` [PATCH v2 05/34] jfs: " 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-30 16:09 ` sashiko-bot
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-30 16:09 ` sashiko-bot
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-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 13/34] hfsplus: don't set SB_RDONLY when creating the attributes tree Christian Brauner
2026-10-30 16:09 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 14/34] affs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 15/34] ufs: " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
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-30 16:10 ` sashiko-bot
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-30 16:10 ` sashiko-bot
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-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 21/34] zonefs: don't set SB_RDONLY after I/O errors Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 22/34] zonefs: use the generic emergency read-only state Christian Brauner
2026-10-30 16:10 ` sashiko-bot
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-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 24/34] btrfs: don't set SB_RDONLY after filesystem errors Christian Brauner
2026-10-30 16:10 ` sashiko-bot
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 [this message]
2026-10-29 16:07 ` [PATCH v2 27/34] efivarfs: stop using SB_RDONLY for read-only efivar ops Christian Brauner
2026-10-30 16:10 ` sashiko-bot
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-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 30/34] ext4: allow remounting read-only in the emergency state Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 31/34] ext4: use the generic emergency read-only state Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 32/34] selftests/filesystems: test ext4 remounts in the emergency state Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 33/34] xfs: allow remounting read-only after a shutdown Christian Brauner
2026-10-30 16:10 ` sashiko-bot
2026-10-29 16:07 ` [PATCH v2 34/34] selftests/filesystems: test xfs remounts " Christian Brauner
2026-10-30 16:10 ` sashiko-bot
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=sashiko-outbox-191245@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=brauner@kernel.org \
--cc=dsterba@suse.cz \
--cc=jack@suse.com \
--cc=jlbec@evilplan.org \
--cc=joseph.qi@linux.alibaba.com \
--cc=linux-efi@vger.kernel.org \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-mtd@lists.infradead.org \
--cc=mark@fasheh.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=tytso@mit.edu \
--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