[PATCH v1 4/5] ntfs: write unlinked file attributes before dropping their cache

From: Baolin Liu

Date: Tue Oct 27 2026 - 05:36:48 EST


From: Xuewen Wang <wangxuewen@xxxxxxxxxx>

Attribute inodes copy the base inode's link count when initialized.
Those initialized after the base file is unlinked have zero links and
are evicted at the final iput(). Nonresident attribute writes can leave
dirty pages in that cache, so an immediately following getxattr can fail
to find a successfully written EA.

Use the synchronous nonresident attribute write path when the base inode
has no links. Keep named data streams on their existing I/O path. This
allows anonymous files to prepare nonresident EAs without retaining
attribute inodes that would pin the base inode and prevent its
reclamation.

Signed-off-by: Xuewen Wang <wangxuewen@xxxxxxxxxx>
---
Tested with the complete five-patch series in QEMU. A 12000-byte EA on
both an ordinary open-unlinked file and an unpublished O_TMPFILE can be
read back immediately, matching every written byte. The published file's
EA also matches after cache eviction, remount and a fresh boot.
Offline checks found the recorded base MFT records' in-use flags and
MFT bitmap bits clear after closing unpublished files, including one
with nonresident data and EAs.

fs/ntfs/inode.c | 8 ++++++++
1 file changed, 8 insertions(+)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 206db4e..3c2bbbd 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -4037,6 +4037,14 @@ s64 ntfs_inode_attr_pwrite(struct inode *vi, s64 pos, s64 count, u8 *buf, bool s

WARN_ON(!NInoAttr(ni));

+ /*
+ * Attribute inodes of an unlinked file have no links either and are
+ * evicted at the final iput(). Do not leave their data in dirty pages
+ * that eviction would discard while the base file is still open.
+ */
+ if (!VFS_I(base_ni)->i_nlink && !ntfs_inode_is_named_stream(ni))
+ sync = true;
+
if (ntfs_inode_is_named_stream(ni)) {
if (NInoEncrypted(ni))
return -EACCES;