[PATCH AUTOSEL 6.18-6.12] fs/ntfs3: check for shutdown in fsync

Sasha Levin
2025-12-06T14:02:58Z

From: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>

[ Upstream commit 1b2ae190ea43bebb8c73d21f076addc8a8c71849 ]

Ensure fsync() returns -EIO when the ntfs3 filesystem is in forced
shutdown, instead of silently succeeding via generic_file_fsync().

Signed-off-by: Konstantin Komarov <almaz.alexandrovich@paragon-software.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

## Analysis Summary

### What the commit does:
Adds a new wrapper function `ntfs_file_fsync()` that checks if the ntfs3
filesystem is in forced shutdown state before calling
`generic_file_fsync()`. If the filesystem is shutting down, it returns
`-EIO` instead of silently succeeding.

### Technical mechanism:
The fix is straightforward:
1. Get the inode from the file
2. Call `ntfs3_forced_shutdown(inode->i_sb)` to check if filesystem is
in error state
3. Return `-EIO` if true, otherwise delegate to `generic_file_fsync()`

### Is this a real bug fix?
**Yes** - this fixes a data integrity semantics issue. When a filesystem
is in forced shutdown (typically after critical I/O errors), fsync()
should return an error to inform applications their data was not synced.
Silently succeeding could cause data loss without applications knowing.

### Stable kernel criteria evaluation:

| Criteria | Assessment |
|----------|------------|
| Fixes real bug | Yes - data integrity semantics issue |
| Small/contained | Yes - ~10 lines, single function |
| Obviously correct | Yes - follows existing pattern in ntfs3 |
| Stable tag | **NO** - maintainer didn't request stable |
| Fixes: tag | **NO** - no indication of when bug was introduced |

### Critical dependency issue:
The `ntfs3_forced_shutdown()` function was introduced in **kernel 6.8**
(commit 6c3684e703837). My verification shows:
- **v6.6**: Does NOT have `ntfs3_forced_shutdown` (0 occurrences)
- **v6.8+**: Has the shutdown infrastructure

This means:
- Stable trees **6.6.y**, **6.1.y**, **5.15.y**, etc. cannot use this
fix without first backporting the entire shutdown feature (~75 lines
across 7 files)
- Only newer stable trees (if any exist based on 6.8+) would benefit

### Risk vs Benefit:
- **Benefit**: Correct fsync() error handling during filesystem shutdown
- **Risk**: Low for applicable kernels - simple logic, well-tested
pattern
- **Applicability**: Very limited - only affects recent kernels with
shutdown support

### Conclusion:
While this is a legitimate fix for a data integrity issue, several
factors argue against backporting:

1. **No maintainer request**: No "Cc: stable@vger.kernel.org" tag
indicates the maintainer didn't consider this critical for stable
2. **Dependency on new feature**: Requires the shutdown infrastructure
from 6.8, which is not in most active stable trees (6.6.y, 6.1.y,
5.15.y)
3. **Limited impact scope**: Only applies to the relatively recent
kernel versions that have the shutdown feature
4. **The shutdown feature itself is new**: The forced shutdown
functionality only existed for a short time before this fix, meaning
the exposure window is small

This fix would require significant infrastructure backporting to be
useful in most stable trees, making it unsuitable as-is for stable
backporting.

**NO**

fs/ntfs3/file.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)

diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c
index 4c90ec2fa2eae..83f0072f0896c 100644
--- a/fs/ntfs3/file.c
+++ b/fs/ntfs3/file.c
@@ -1375,6 +1375,18 @@ static ssize_t ntfs_file_splice_write(struct pipe_inode_info *pipe,
return iter_file_splice_write(pipe, file, ppos, len, flags);
}

+/*
+ * ntfs_file_fsync - file_operations::fsync
+ */
+static int ntfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
+{
+ struct inode *inode = file_inode(file);
+ if (unlikely(ntfs3_forced_shutdown(inode->i_sb)))
+ return -EIO;
+
+ return generic_file_fsync(file, start, end, datasync);
+}
+
// clang-format off
const struct inode_operations ntfs_file_inode_operations = {
.getattr = ntfs_getattr,
@@ -1397,7 +1409,7 @@ const struct file_operations ntfs_file_operations = {
.splice_write = ntfs_file_splice_write,
.mmap_prepare = ntfs_file_mmap_prepare,
.open = ntfs_file_open,
- .fsync = generic_file_fsync,
+ .fsync = ntfs_file_fsync,
.fallocate = ntfs_fallocate,
.release = ntfs_file_release,
};
--
2.51.0