[PATCH] ntfs: include the final partial cluster in sync writes

Karl Mehltretter posted 1 patch 2 days, 11 hours ago
fs/ntfs/inode.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
[PATCH] ntfs: include the final partial cluster in sync writes
Posted by Karl Mehltretter 2 days, 11 hours ago
ntfs_attrlist_repack() synchronously writes the replacement attribute
list before updating its mapping pairs and freeing the old run. With
512-byte clusters, a 544-byte list submits a 512-byte bio, but the
write returns 544 and repack accepts it as complete. If the later
buffered update does not reach disk, the replacement list lacks its
final 32 bytes.

__ntfs_inode_non_resident_attr_pwrite() converts attr_len to clusters
with ntfs_bytes_to_cluster(), which rounds down. Before repack, its
synchronous callers used either cluster-aligned lengths or lengths
smaller than one cluster, where max_t() selects one.

Round attr_len up so repack writes the final partial cluster before
publishing the new mapping pairs.

Fixes: b1d732e62a5b ("ntfs: repack $MFT/$ATTRIBUTE LIST")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
Built fs/ntfs/ at 444c7dc82415 with W=1 and NTFS_FS=m for x86_64 and
i386 using GCC 15.2.0. Both builds completed without warnings.

Runtime-tested with QEMU 10.2.1, x86_64 TCG and virtio-blk cache=none
on 4904082812d5, a v7.2.7 stable queue containing b1d732e62a5b. Test
hooks called the normal unlocked update, forced the optional expansion
to return -ENOSPC and used a 64 KiB reserve on a 16 MiB image.

With 512-byte clusters and a 544-byte list, both kernels paused after
repack and before the buffered update. The old code submitted 512 bytes,
returned 544 and left a marker in the second cluster unchanged. The
fixed code submitted 1024 bytes and wrote the exact 32-byte tail. A
1024-byte list wrote exactly two clusters and left a marker in the
third cluster unchanged.

A test hook returned -EIO instead of submitting the 1024-byte BIO. The
rollback restored the original mapping and all 544 bytes, and freed the
entire replacement run. The image cleanly unmounted and remounted
with the unmodified queue kernel.

Runtime coverage was limited to the repack caller, which writes at
offset zero.

The base's scripts/checkpatch.pl --strict reports no findings.

 fs/ntfs/inode.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c
index cadf623d54d48..d8d3a7b7b8a9a 100644
--- a/fs/ntfs/inode.c
+++ b/fs/ntfs/inode.c
@@ -3761,7 +3761,9 @@ static s64 __ntfs_inode_non_resident_attr_pwrite(struct inode *vi,
 			struct runlist_element *rl;
 			int bio_err;
 
-			lcn_count = max_t(s64, 1, ntfs_bytes_to_cluster(vol, attr_len));
+			lcn_count = max_t(s64, 1,
+					  ntfs_bytes_to_cluster(vol, attr_len +
+								vol->cluster_size - 1));
 			vcn = ntfs_pidx_to_cluster(vol, folio->index);
 
 			do {

base-commit: 444c7dc82415a353b57e43189f276124cc5fd785
-- 
2.53.0
Re: [PATCH] ntfs: include the final partial cluster in sync writes
Posted by Namjae Jeon 2 days, 2 hours ago
On Tue, Sep 22, 2026 at 1:33 PM Karl Mehltretter <kmehltretter@gmail.com> wrote:
>
> ntfs_attrlist_repack() synchronously writes the replacement attribute
> list before updating its mapping pairs and freeing the old run. With
> 512-byte clusters, a 544-byte list submits a 512-byte bio, but the
> write returns 544 and repack accepts it as complete. If the later
> buffered update does not reach disk, the replacement list lacks its
> final 32 bytes.
>
> __ntfs_inode_non_resident_attr_pwrite() converts attr_len to clusters
> with ntfs_bytes_to_cluster(), which rounds down. Before repack, its
> synchronous callers used either cluster-aligned lengths or lengths
> smaller than one cluster, where max_t() selects one.
>
> Round attr_len up so repack writes the final partial cluster before
> publishing the new mapping pairs.
>
> Fixes: b1d732e62a5b ("ntfs: repack $MFT/$ATTRIBUTE LIST")
> Cc: stable@vger.kernel.org
> Assisted-by: LLM
> Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Applied it to #ntfs-next.
Thanks!