[PATCH v4 4/4] ntfs: persist the dirty state after the final put_super() commits
From: Hongling Zeng
Date: Tue Sep 08 2026 - 22:31:44 EST
The just-in-case mftmirr/mft commits and the final write_inode_now()
in ntfs_put_super() can record NVolErrors() after the dirty state has
been persisted, so errors from those points would leave the volume
unmounted with a clean on-disk dirty bit - contradicting the "cannot
unmount clean" guarantee ntfs_sync_volume_dirty_state() is meant to
provide.
Move the persistence to the end of ntfs_put_super(): keep the gated
re-commits and the tail commits where they are, run
ntfs_sync_volume_dirty_state() and the $Volume commit after the last
write_inode_now(), and move the iput(vol->vol_ino) down so
vol->vol_ino stays available for the sync.
Reported-by: Baolin Wang <baolin.wang@xxxxxxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Hongling Zeng <zenghongling@xxxxxxxxxx>
---
fs/ntfs/super.c | 52 +++++++++++++++++++++++++++++--------------------
1 file changed, 31 insertions(+), 21 deletions(-)
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c
index 4b4af1ea8b09..b31ea2747f57 100644
--- a/fs/ntfs/super.c
+++ b/fs/ntfs/super.c
@@ -1826,26 +1826,13 @@ static void ntfs_put_super(struct super_block *sb)
ntfs_commit_inode(vol->mft_ino);
/*
- * If a read-write mount, persist the error state in the volume flags:
- * mark the volume clean if no volume errors have occurred, and make
- * sure VOLUME_IS_DIRTY is on disk if any have, so chkdsk runs on the
- * next mount. Also, re-commit all affected inodes.
+ * If a read-write mount, re-commit all affected inodes once more.
+ * The dirty state itself is persisted at the end of ntfs_put_super(),
+ * after the last commits and the final write_inode_now(): those can
+ * still record errors via __ntfs_write_inode(), and the sync must
+ * evaluate NVolErrors() with the last setter already run.
*/
if (!sb_rdonly(sb)) {
- if (ntfs_sync_volume_dirty_state(vol)) {
- ntfs_warning(sb,
- "Failed to sync dirty bit in volume information flags. Run chkdsk.");
- } else if (NVolErrors(vol)) {
- /*
- * The dirty bit is on disk now; only warn when the
- * sync actually succeeded, or this message would
- * contradict the one above.
- */
- ntfs_warning(sb,
- "Volume has errors. Leaving volume marked dirty. Run chkdsk.");
- }
- /* Commits the updated volume flags if they were written. */
- ntfs_commit_inode(vol->vol_ino);
if (!NVolErrors(vol)) {
ntfs_commit_inode(vol->root_ino);
if (vol->mftmirr_ino)
@@ -1854,9 +1841,6 @@ static void ntfs_put_super(struct super_block *sb)
}
}
- iput(vol->vol_ino);
- vol->vol_ino = NULL;
-
/* NTFS 3.0+ specific clean up. */
if (vol->major_ver >= 3) {
if (vol->extend_ino) {
@@ -1897,10 +1881,36 @@ static void ntfs_put_super(struct super_block *sb)
ntfs_commit_inode(vol->mft_ino);
write_inode_now(vol->mft_ino, 1);
+ /*
+ * If a read-write mount, persist the error state in the volume flags:
+ * mark the volume clean if no volume errors have occurred, and make
+ * sure VOLUME_IS_DIRTY is on disk if any have, so chkdsk runs on the
+ * next mount.
+ */
+ if (!sb_rdonly(sb)) {
+ if (ntfs_sync_volume_dirty_state(vol)) {
+ ntfs_warning(sb,
+ "Failed to sync dirty bit in volume information flags. Run chkdsk.");
+ } else if (NVolErrors(vol)) {
+ /*
+ * The dirty bit is on disk now; only warn when the
+ * sync actually succeeded, or this message would
+ * contradict the one above.
+ */
+ ntfs_warning(sb,
+ "Volume has errors. Leaving volume marked dirty. Run chkdsk.");
+ }
+ /* Commits the updated volume flags if they were written. */
+ ntfs_commit_inode(vol->vol_ino);
+ }
+
iput(vol->mft_ino);
vol->mft_ino = NULL;
blkdev_issue_flush(sb->s_bdev);
+ iput(vol->vol_ino);
+ vol->vol_ino = NULL;
+
ntfs_volume_free(vol);
}
--
2.25.1