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

From: Baolin Liu

Date: Sat Oct 31 2026 - 01:31:11 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 the standalone five-patch series in QEMU with a 12000-byte EA on
an unlinked file. Attribute writeback and cleanup completed; published
EA contents also survived cache eviction, remount and reboot.

No functional change from v1.

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

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index 62dd5bd5bb81..2b1388de7bb2 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -4052,6 +4052,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;