* [PATCH] ntfs: handle a failed size rollback in the write error path
@ 2026-10-04 2:48 Hongling Zeng
2026-10-06 5:53 ` Hyunchul Lee
0 siblings, 1 reply; 2+ messages in thread
From: Hongling Zeng @ 2026-10-04 2:48 UTC (permalink / raw)
To: linkinjeon, hyc.lee; +Cc: ntfs, linux-kernel, zhongling0719, Hongling Zeng
ntfs_file_write_iter() extends the data and initialized sizes before
it copies the user data and restores them when the write then fails.
The restoration is best-effort: both results are discarded, even
though the extension is already recorded in the dirty MFT record.
When the restoration fails too, the extended sizes reach the disk
while the VFS inode keeps reporting the old ones: after a remount the
file appears grown again, with an uninitialized tail where the failed
write never put any data, and nothing records the failure.
Keep both undo results: on failure, set NVolSetErrors(), which the next
persistence point persists as VOLUME_IS_DIRTY, and log a message for
the errors= policy.
Fixes: 9c87959601e8 ("ntfs: update file operations")
Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
---
fs/ntfs/file.c | 29 +++++++++++++++++++++++++++--
1 file changed, 27 insertions(+), 2 deletions(-)
diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
index 3ec82715a588..b5b30e44ac51 100644
--- a/fs/ntfs/file.c
+++ b/fs/ntfs/file.c
@@ -678,14 +678,39 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
&ntfs_iomap_folio_ops, NULL);
out:
if (ret < 0 && ret != -EIOCBQUEUED) {
+ int undo_err = 0;
+
if (ni->initialized_size != old_init_size) {
+ int init_err;
+
mutex_lock(&ni->mrec_lock);
- ntfs_attr_set_initialized_size(ni, old_init_size);
+ init_err = ntfs_attr_set_initialized_size(ni,
+ old_init_size);
mutex_unlock(&ni->mrec_lock);
+ if (init_err && !undo_err)
+ undo_err = init_err;
}
if (ni->data_size != old_data_size) {
+ int data_err;
+
truncate_setsize(vi, old_data_size);
- ntfs_attr_truncate(ni, old_data_size);
+ data_err = ntfs_attr_truncate(ni, old_data_size);
+ if (data_err && !undo_err)
+ undo_err = data_err;
+ }
+ if (undo_err) {
+ /*
+ * The extension is recorded in the dirty MFT
+ * record already, so a failed rollback leaves the
+ * new sizes on disk while the VFS inode keeps
+ * reporting the old ones. Record the error: the
+ * next persistence point persists it as
+ * VOLUME_IS_DIRTY. Run chkdsk.
+ */
+ NVolSetErrors(vol);
+ ntfs_error(vi->i_sb,
+ "Failed to roll back the size update: %d",
+ undo_err);
}
}
out_lock:
--
2.25.1
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [PATCH] ntfs: handle a failed size rollback in the write error path
2026-10-04 2:48 [PATCH] ntfs: handle a failed size rollback in the write error path Hongling Zeng
@ 2026-10-06 5:53 ` Hyunchul Lee
0 siblings, 0 replies; 2+ messages in thread
From: Hyunchul Lee @ 2026-10-06 5:53 UTC (permalink / raw)
To: Hongling Zeng; +Cc: linkinjeon, ntfs, linux-kernel, zhongling0719
On Sun, Oct 04, 2026 at 10:48:22AM +0800, Hongling Zeng wrote:
> ntfs_file_write_iter() extends the data and initialized sizes before
> it copies the user data and restores them when the write then fails.
> The restoration is best-effort: both results are discarded, even
> though the extension is already recorded in the dirty MFT record.
> When the restoration fails too, the extended sizes reach the disk
> while the VFS inode keeps reporting the old ones: after a remount the
> file appears grown again, with an uninitialized tail where the failed
> write never put any data, and nothing records the failure.
>
> Keep both undo results: on failure, set NVolSetErrors(), which the next
> persistence point persists as VOLUME_IS_DIRTY, and log a message for
> the errors= policy.
>
> Fixes: 9c87959601e8 ("ntfs: update file operations")
> Signed-off-by: Hongling Zeng <zenghongling@kylinos.cn>
> ---
> fs/ntfs/file.c | 29 +++++++++++++++++++++++++++--
> 1 file changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c
> index 3ec82715a588..b5b30e44ac51 100644
> --- a/fs/ntfs/file.c
> +++ b/fs/ntfs/file.c
> @@ -678,14 +678,39 @@ static ssize_t ntfs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
> &ntfs_iomap_folio_ops, NULL);
> out:
> if (ret < 0 && ret != -EIOCBQUEUED) {
> + int undo_err = 0;
> +
> if (ni->initialized_size != old_init_size) {
> + int init_err;
> +
> mutex_lock(&ni->mrec_lock);
> - ntfs_attr_set_initialized_size(ni, old_init_size);
> + init_err = ntfs_attr_set_initialized_size(ni,
> + old_init_size);
I think the rollback needs to distinguish resident and compressed
attributes.
If the data attribute is still resident,
ntfs_attr_set_initialized_size() always return -EINVAL.
> mutex_unlock(&ni->mrec_lock);
> + if (init_err && !undo_err)
> + undo_err = init_err;
> }
> if (ni->data_size != old_data_size) {
> + int data_err;
> +
> truncate_setsize(vi, old_data_size);
> - ntfs_attr_truncate(ni, old_data_size);
> + data_err = ntfs_attr_truncate(ni, old_data_size);
And ntfs_attr_truncate() always return -EOPNOTSUPP for a compressed
attribute.
> + if (data_err && !undo_err)
> + undo_err = data_err;
> + }
> + if (undo_err) {
> + /*
> + * The extension is recorded in the dirty MFT
> + * record already, so a failed rollback leaves the
> + * new sizes on disk while the VFS inode keeps
> + * reporting the old ones. Record the error: the
> + * next persistence point persists it as
> + * VOLUME_IS_DIRTY. Run chkdsk.
> + */
> + NVolSetErrors(vol);
> + ntfs_error(vi->i_sb,
> + "Failed to roll back the size update: %d",
> + undo_err);
> }
> }
> out_lock:
> --
> 2.25.1
>
--
Thanks,
Hyunchul
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-06 5:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-04 2:48 [PATCH] ntfs: handle a failed size rollback in the write error path Hongling Zeng
2026-10-06 5:53 ` Hyunchul Lee
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®