From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794065126; b=UxyInaWze1W49hYbNfjxGmJIKlv6WhgFT4MKeErHrAfQ/0MDch2oYAeg+837X/oItGIg YsXU0uGULYhSMwP0BHb/Goe2KJQtG0OLTTiXR21FAZpmJrMA1PH/eVgE4ErZ3y4SPN+NW ualOPVwrOlzVkBtE/rsxOwjl7qHJb//zJ+FSi3ykW5zRxrKqayh0E8wzij2aRQN3Hb2ON hcMcodEeQDmuh4VjqdQTpUVTbyDOEWHBSNkTPJOq4Hd7uC1f7ylS8Crkw35VwNmXzVh1Y drn7yL31gK6U+I1dVuhuZiw7HcX05sA6PslYNVWNsotqzUOCmr2S2sKvjf8eixI6a9g== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794065126; h=Received:DKIM-Signature:From:To:Cc:Subject:Date:Message-ID:X-Mailer: In-Reply-To:References:User-Agent:X-stable:X-Patchwork-Hint: MIME-Version:Content-Transfer-Encoding; bh=clOSdL3Ulzmse9czI1sKwy3viecDxLzwOxs3VMEZ8RM=; b=pz5NS0hUITeDriKiNeA3fI6u3mSQOVlvab76DjKtN5aiQ2vLyEAxQBMmWFbhbWeqSq8B UAncs7pp/ETIqYZcF+SoPQJLTQAaMlcwcF+0AQ//CevFBQmM+AiZV+9HYpgyVdIDv+dmE Q5ORGuEaMjFYkX3g2zwYHQiSJoqXMH+B0CEzXTitBWvmHdbySSLtRSsuQ0esA+YZM9Og9 pjxSABYMzPEUT2KnYT5orl4XGt+qDyWLQIPHT0W9EK/Gylnp3KUyxDGVaiifxLU776iZ5 axeCISf+Uq5a60er1Xvua7009fWbKwnB1Ly9OmLR9bmiWyAi3PMfF/UZa0gIlKcX+oQ== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=xgF7XM2T; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 54B88606A32D; Sat, 7 Nov 2026 15:25:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.a=rsa-sha256 header.s=korg header.b=xgF7XM2T Received: by smtp.kernel.org (Postfix) with ESMTPSA id 005871F0089F; Sat, 7 Nov 2026 15:25:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linuxfoundation.org; s=korg; t=1794065126; bh=clOSdL3Ulzmse9czI1sKwy3viecDxLzwOxs3VMEZ8RM=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=xgF7XM2TidpJAgjlLTqkOoimVl/jIvvfQwhVOA3faB3bem6L9BGElvGKVxpH9mo8w ttrruwORU0e+6yV5fwDoeXeoSDsqY9vbXPJTOVvsEn1S+crrWaF4LPbIhc2s81l9RX fiQuIRY5E8SacS1fk2vk/uSMYvOf3eFUvVSeSlQM= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, Baolin Liu , Hongling Zeng , Hyunchul Lee , Namjae Jeon , Sasha Levin Subject: [PATCH 7.3 0922/1257] ntfs: do not clear the volume dirty bit during sync Date: Sat, 7 Nov 2026 08:53:38 -0500 Message-ID: <20261107135004.819864153@linuxfoundation.org> X-Mailer: git-send-email 2.56.0 In-Reply-To: <20261107134939.434104957@linuxfoundation.org> References: <20261107134939.434104957@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore X-Mailing-List: stable@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Hongling Zeng [ Upstream commit 4a1bb54f571cbef67a7c470a3139ffec1a15a8e4 ] ntfs_sync_fs() clears VOLUME_IS_DIRTY while the volume is still mounted read-write, so a sync running concurrently with an in-flight metadata modification can clear and persist a bit that was just set: the modification then lands on a volume that is clean on disk, and a crash does not run chkdsk. Stop clearing the bit in ntfs_sync_fs() and leave the clearing to the remount-to-read-only path, which the VFS reaches only after sb_prepare_remount_readonly() has drained in-flight writers, and to ntfs_put_super(), which runs after evict_inodes() on a quiesced filesystem. A mounted read-write volume now keeps the dirty bit until it is dismounted cleanly, which matches the NTFS semantics; the cost is a needless chkdsk if the machine crashes between a sync and the unmount. A recorded error state is still persisted right away when the filesystem is synced: with NVolErrors() set, ntfs_sync_volume_dirty_state() can only set the bit, never clear it, so it cannot lose a modification the way the old unconditional call did. This keeps the error report from being lost to a crash on a volume that has seen no modification; an error recorded after the last sync is still only persisted at the next quiescent transition. sync_blockdev() and blkdev_issue_flush() are both called and the first error is returned, so a writeback failure neither hides a flush failure nor skips it. A RWF_NOWAIT write still blocks in the marking when the volume looks clean, as it already did on the base; a non-blocking marking is follow-up work. Reported-by: Baolin Liu Cc: stable@vger.kernel.org Signed-off-by: Hongling Zeng Reviewed-by: Hyunchul Lee Reviewed-by: Baolin Liu Signed-off-by: Namjae Jeon Signed-off-by: Sasha Levin --- fs/ntfs/file.c | 7 ++++--- fs/ntfs/super.c | 31 ++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index e3020a4bf805a..e290616be07d0 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -637,9 +637,10 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) /* * The volume must be marked dirty before the modification is made, - * without an unlocked check of the in-memory flag: ntfs_sync_fs() - * can clear the bit concurrently and the modification would then - * land on a volume that is clean on disk. + * without an unlocked check of the in-memory flag: the dirty bit + * is only cleared at the quiescent transitions, under the same + * $Volume mrec_lock this call takes, so an unlocked skip could + * lose the set to one of them. */ ntfs_set_volume_flags(vol, VOLUME_IS_DIRTY); diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index e13ede3cd836f..c3d73cd6909eb 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -493,8 +493,9 @@ int ntfs_set_volume_flags(struct ntfs_volume *vol, __le16 flags) * This is the single point that persists the in-memory error state to disk. * The runtime error paths only record NVolErrors() because they run under a * variety of ntfs locks the dirty-bit write cannot be taken under (runlist - * locks, vol->lcnbmp_lock, vol->mftbmp_lock, mrec_locks); the first - * ntfs_sync_fs(), a remount, or the unmount then persists the flag here. + * locks, vol->lcnbmp_lock, vol->mftbmp_lock, mrec_locks); a sync of a + * volume with recorded errors, a remount to read-only, or the unmount, + * then persists the flag here. * * A hibernated volume is not written from these persistence paths: * resuming Windows from a modified image corrupts it, so the dirty bit @@ -2029,7 +2030,7 @@ static void ntfs_shutdown(struct super_block *sb) static int ntfs_sync_fs(struct super_block *sb, int wait) { struct ntfs_volume *vol = NTFS_SB(sb); - int err = 0; + int ret, err = 0; if (NVolShutdown(vol)) return -EIO; @@ -2037,14 +2038,30 @@ static int ntfs_sync_fs(struct super_block *sb, int wait) if (!wait) return 0; - /* If there are some dirty buffers in the bdev inode */ - if (ntfs_sync_volume_dirty_state(vol)) { + /* + * The volume dirty bit is deliberately not cleared here: a sync + * running concurrently with an in-flight modification could clear + * and persist a bit that was just set, leaving the modification + * on a volume that is clean on disk. The bit is only cleared at + * the quiescent state transitions, remounting read-only and clean + * unmount. A recorded error state, however, is persisted right + * away so that it is not lost to a crash on a volume that has + * seen no modification; with NVolErrors() set this can only set + * the bit, never clear it. + */ + if (NVolErrors(vol) && + ntfs_sync_volume_dirty_state(vol)) { ntfs_warning(sb, "Failed to sync dirty bit in volume information flags. Run chkdsk."); err = -EIO; } sync_inodes_sb(sb); - sync_blockdev(sb->s_bdev); - blkdev_issue_flush(sb->s_bdev); + ret = sync_blockdev(sb->s_bdev); + if (ret && !err) + err = ret; + + ret = blkdev_issue_flush(sb->s_bdev); + if (ret && !err) + err = ret; return err; } -- 2.53.0