Linux EXT4 FS development
 help / color / mirror / Atom feed
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

  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