From: guzebing <guzebing1612@gmail.com>
To: linux-ext4@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: tytso@mit.edu, adilger.kernel@dilger.ca,
libaokun@linux.alibaba.com, jack@suse.cz, ojaswin@linux.ibm.com,
ritesh.list@gmail.com, yi.zhang@huawei.com, bretznic@gmail.com,
guzebing <guzebing1612@gmail.com>,
stable@vger.kernel.org
Subject: [PATCH] ext4: reject delalloc to nodelalloc before applying remount options
Date: Fri, 14 Aug 2026 11:48:55 +0800 [thread overview]
Message-ID: <20260814034855.1573759-1-guzebing1612@gmail.com> (raw)
Commit 97f5ec3b166d ("ext4: prevent delalloc to nodelalloc on
remount") rejects switching a mounted filesystem from delalloc to
nodelalloc. However, it performs the check after ext4_apply_options()
has already cleared EXT4_MOUNT_DELALLOC in the live superblock. The
failure path eventually restores the bit, but leaves a window where
other CPUs can observe nodelalloc.
test_opt() reads s_mount_opt directly without a lock shared with
remount. If a concurrent truncate's __es_remove_extent() hits this
window and observes nodelalloc, it sets count_reserved to false.
Delayed extent status entries are then removed without calculating
their cluster reservations, leaving reserved at zero.
ext4_es_remove_extent() therefore calls ext4_da_release_space() with
zero, leaving i_reserved_data_blocks and s_dirtyclusters_counter
elevated. When the inode is later evicted after unlink,
ext4_destroy_inode() reports:
i_reserved_data_blocks (...) not cleared!
CPU 0 CPU 1
ksys_truncate()
...
ext4_es_remove_extent()
ext4_reconfigure()
ext4_check_opt_consistency()
__ext4_remount()
ext4_apply_options()
clear EXT4_MOUNT_DELALLOC
__es_remove_extent()
test_opt() sees !DELALLOC
count_reserved = false
reject delalloc -> nodelalloc
restore EXT4_MOUNT_DELALLOC
remove delayed ES
ext4_da_release_space(0)
Follow the pre-apply validation approach used by
ext4_check_quota_consistency() and reject the transition in
ext4_check_opt_consistency(), before ext4_apply_options() changes live
state. Use mask_s_mount_opt to determine whether delalloc/nodelalloc
was specified and ctx_test_mount_opt() to check the final parsed value.
Fixes: 97f5ec3b166d ("ext4: prevent delalloc to nodelalloc on remount")
Cc: stable@vger.kernel.org
Signed-off-by: guzebing <guzebing1612@gmail.com>
---
This issue was first observed in a production environment. It can now
be reproduced with a shell script.
1. Create a 768 MiB ext4 filesystem and mount it with delalloc.
2. Start 16 workers. Each worker repeatedly runs:
xfs_io -f -c 'pwrite -q 0 32m' file-N
truncate -s 262144 file-N
3. In parallel, repeatedly run "mount -o remount,nodelalloc". Every
remount is expected to fail.
4. Continuously sample the live mount options with findmnt and record
any transient nodelalloc state.
5. After 300 seconds, stop the workers and unmount the filesystem,
then inspect dmesg for "i_reserved_data_blocks (...) not cleared!".
On an affected kernel, 7 transient nodelalloc samples and 9 reservation
warnings were observed during 101 rejected remounts.
With this fix, no transient nodelalloc state or reservation warning was
observed.
fs/ext4/super.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 245f67d10ded3..9e1ea94664775 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -2816,6 +2816,14 @@ static int ext4_check_opt_consistency(struct fs_context *fc,
}
if (is_remount) {
+ if (test_opt(sb, DELALLOC) &&
+ (ctx->mask_s_mount_opt & EXT4_MOUNT_DELALLOC) &&
+ !ctx_test_mount_opt(ctx, EXT4_MOUNT_DELALLOC)) {
+ ext4_msg(sb, KERN_ERR,
+ "can't disable delalloc during remount");
+ return -EINVAL;
+ }
+
if (!sbi->s_journal &&
ctx_test_mount_opt(ctx, EXT4_MOUNT_DATA_ERR_ABORT)) {
ext4_msg(NULL, KERN_WARNING,
@@ -6660,13 +6668,6 @@ static int __ext4_remount(struct fs_context *fc, struct super_block *sb)
goto restore_opts;
}
- if ((old_opts.s_mount_opt & EXT4_MOUNT_DELALLOC) &&
- !test_opt(sb, DELALLOC)) {
- ext4_msg(sb, KERN_ERR, "can't disable delalloc during remount");
- err = -EINVAL;
- goto restore_opts;
- }
-
sb->s_flags = (sb->s_flags & ~SB_POSIXACL) |
(test_opt(sb, POSIX_ACL) ? SB_POSIXACL : 0);
next reply other threads:[~2026-08-14 3:49 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-14 3:48 guzebing [this message]
2026-08-14 5:13 ` [PATCH] ext4: reject delalloc to nodelalloc before applying remount options sashiko-bot
2026-08-14 7:41 ` Ojaswin Mujoo
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=20260814034855.1573759-1-guzebing1612@gmail.com \
--to=guzebing1612@gmail.com \
--cc=adilger.kernel@dilger.ca \
--cc=bretznic@gmail.com \
--cc=jack@suse.cz \
--cc=libaokun@linux.alibaba.com \
--cc=linux-ext4@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=ojaswin@linux.ibm.com \
--cc=ritesh.list@gmail.com \
--cc=stable@vger.kernel.org \
--cc=tytso@mit.edu \
--cc=yi.zhang@huawei.com \
/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