[PATCH 1/2] ntfs: write back the truncated range before dropping it

From: Hongling Zeng

Date: Tue Sep 15 2026 - 02:28:11 EST


On a truncate, ntfs_setattr_size() drops the page cache beyond the new
size with truncate_setsize() and only then updates the attribute on
disk. If that update fails, the size is reverted and the data beyond
the new size becomes visible again -- but the pages were already
dropped, and dirty data in them is lost, even though the truncate, the
operation the user asked for, never happened.

Write the range back before dropping it. If the writeback fails, fail
the truncate with that error and keep the page cache intact; if the
on-disk truncation fails afterwards, the reverted size can be re-read
from disk.

Fixes: 9c87959601e8 ("ntfs: update file operations")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Hongling Zeng <zenghongling@xxxxxxxxxx>
---
fs/ntfs/file.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)

diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 007d1614b9ac..1417a76788ed 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -283,12 +283,27 @@ static int ntfs_setattr_size(struct inode *vi, struct iattr *attr)
i_size_write(vi, attr->ia_size);
pagecache_isize_extended(vi, old_size, attr->ia_size);
} else {
+ /*
+ * The on-disk truncation below can fail, in which case
+ * the size is reverted and the data beyond the new size
+ * becomes visible again. Write that range back first:
+ * truncate_setsize() drops those pages and dirty data
+ * cannot be recovered afterwards.
+ */
+ if (attr->ia_size < old_size) {
+ err = filemap_write_and_wait_range(vi->i_mapping,
+ attr->ia_size, old_size - 1);
+ if (err)
+ goto out_unlock;
+ }
+
truncate_setsize(vi, attr->ia_size);
}

err = ntfs_truncate_vfs(vi, attr->ia_size, old_size);
if (err)
i_size_write(vi, old_size);
+out_unlock:
filemap_invalidate_unlock(vi->i_mapping);

return err;
--
2.25.1