| Age | Commit message (Collapse) | Author |
|
https://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git
|
|
|
|
NTFS already loads the creation time into i_crtime and reports it through
ntfs_getattr(). However, the symbolic-link inode operations omit getattr,
so statx() with AT_SYMLINK_NOFOLLOW falls back to generic_fillattr() and
does not return STATX_BTIME for the link itself.
Use ntfs_getattr() for symbolic links to expose their stored creation time.
Signed-off-by: Xuewen Wang <wangxuewen@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
NTFS reads the 64-bit volume serial number from the boot sector but leaves
the superblock UUID unset. As a result, the generic FS_IOC_GETFSUUID
handler returns ENOTTY for files and directories on an NTFS volume.
Register the on-disk little-endian serial number as an eight-byte
filesystem identifier with super_set_uuid(). The generic VFS handler can
then expose the existing volume identifier.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_dir_fsync() writes directory metadata and calls sync_blockdev(),
but does not flush the block device write cache. A successful fsync()
can therefore leave the directory's metadata in a volatile device cache.
Issue a cache flush after successful writeback and return any flush error.
This matches the regular-file fsync and syncfs paths.
With QEMU blkdebug injecting -EIO for flush_to_disk, fsync() on an NTFS
directory returned 0 before this change while syncfs() returned -EIO.
After this change, both return -EIO. A kretprobe confirmed the flush
error in the directory fsync path.
Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_file_fsync() calls blkdev_issue_flush() after writeback but discards
its return value. If the device cannot flush its write cache, fsync()
reports success even though the file is not guaranteed to be durable.
Reproduce this with QEMU blkdebug failing flush_to_disk with -EIO.
On ntfs-next at 04fb910da2c8, a kretprobe recorded -EIO from
blkdev_issue_flush() while fsync() returned 0. With this change,
fsync() returns -EIO and logs the failure. The syncfs() path already
reports this error.
Fixes: 9c87959601e8 ("ntfs: update file operations")
Cc: stable@vger.kernel.org
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_index_lookup() returns -ENOENT when ntfs_ia_open() fails to open the
index allocation. This error path leaves icx->ib unset, unlike a missing
key in an otherwise valid index, which returns an insertion context.
ntfs_ie_add() treats -ENOENT as a valid insertion position and dereferences
icx->ib when the lookup is not in the index root. A corrupt $I30 bitmap
attribute can therefore cause a NULL pointer dereference when adding a
directory entry.
Return -EIO for index allocation open failures so insertion aborts through
the existing error path. Keep -ENOENT for genuinely missing keys and
document that other errors leave no valid index entry.
Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations")
Reported-by: 1sh1ro <yangguikun19@qq.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
During reconfiguration, fc->s_fs_info points to a newly allocated
ntfs_volume. It does not contain the mounted volume's stream setting.
Consequently, a windows mount rejects a remount with the same
streams_interface=windows setting, but accepts streams_interface=none
without changing the active pathname interface. This also breaks an
ordinary read-only remount when the existing windows setting is passed
again, for example from fstab.
Compare the requested setting with the mounted volume instead. Report
an unsupported change with ntfs_warning() so it does not invoke the
mounted filesystem's error-handling policy.
Fixes: 2de2cdd9cc08 ("ntfs: add pathname access for named streams")
Signed-off-by: DaeMyung Kang <charsyam@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_decompress() tracks where the current sub-block starts and ends
inside the destination page with two u16s:
u16 do_sb_start;
u16 do_sb_end;
...
do_sb_start = *dest_ofs;
do_sb_end = do_sb_start + NTFS_SB_SIZE;
*dest_ofs is an int page offset masked with ~PAGE_MASK, and
NTFS_SB_SIZE is 0x1000, so do_sb_end needs PAGE_SIZE + 0xfff of range.
That exceeds u16 once PAGE_SIZE reaches 0x10000: the last sub-block of a
page starts at 0xf000 and do_sb_end wraps from 0x10000 to 0.
The zero-fill that pads a short sub-block then computes a negative
length:
if (dp_addr < dp_sb_end) {
int nr_bytes = do_sb_end - *dest_ofs;
memset(dp_addr, 0, nr_bytes);
A sub-block made only of symbol tokens reaches this without consulting
do_sb_end on the way, because that path just does
*dp_addr++ = *cb++;
++*dest_ofs;
and is bounded by dp_addr against dp_sb_end. With do_sb_start at 0xf000
and eight literal bytes emitted, nr_bytes is -61448 and the memset()
runs for 18446744073709490168 bytes.
Getting there is cheap: fifteen sub-blocks of eleven bytes each advance
*dest_ofs to 0xf000, since the same zero-fill pads each of them out to
0x1000 while do_sb_end is still exact, and the sixteenth one triggers
the wrap. A compression block is 0x10000 bytes with 4 KiB clusters and
the fixed compression unit of 4, so all sixteen fit with room to spare.
Phrase tokens are bounded against do_sb_end and so return -EOVERFLOW
instead, and the
if (*dest_index == dest_max_index && do_sb_end > dest_max_ofs)
check at the top of the sub-block stops firing for the same reason.
Use int for both, matching *dest_ofs and dest_max_ofs. The narrow type
came in with the original import and survived the removal and revert of
the driver.
Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_file_read_iter() refuses direct I/O for compressed and WOF
compressed attributes but lets encrypted ones reach iomap_dio_rw().
ntfs_read_iomap_begin_non_resident() has no NInoEncrypted() test, so it
reports IOMAP_MAPPED for the attribute's real clusters and the raw
on-disk ciphertext is copied to the caller. Buffered reads are refused
by ntfs_read_folio(), but direct I/O never calls it.
Fixes: 9c87959601e8 ("ntfs: update file operations")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_read_folio() refuses EFS-encrypted files with -EOPNOTSUPP because
decryption is not implemented. ntfs_readahead() has no NInoEncrypted()
test and passes them to iomap_readahead(), which maps the runlist and
fills the folios with the raw on-disk ciphertext. The folios are
marked uptodate, so the read that follows never reaches ->read_folio
and returns ciphertext instead of -EOPNOTSUPP.
ntfs_read_locked_inode() sets NInoEncrypted() and NInoNonResident() for
a non-resident encrypted $DATA attribute and rejects the
encrypted-and-compressed combination, so none of the three existing
conditions fires. read(), mmap(), splice() and fadvise() all populate
the page cache through readahead.
Skipping readahead leaves the folio unpopulated, so the read falls back
to ntfs_read_folio() and gets the intended error.
Fixes: b041ca562526 ("ntfs: update iomap and address space operations")
Signed-off-by: Zhan Xusheng <zhanxusheng@xiaomi.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Store nodump in bit 2 of LINUXFLAGS and allow it through fileattr_set.
Report the cached persistent bit through fileattr_get and
STATX_ATTR_NODUMP, including the statx supported-attribute mask. Reuse
the existing EA update and inode-load paths; nodump needs no additional
inode flag enforcement.
Document the complete immutable, append-only and nodump bitmask.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Extend the persistent fileattr interface to append-only using bit 1 of
LINUXFLAGS. Restore S_APPEND on inode load and update it after
successful EA writes. Include append in the known-bit mask while
retaining all other unknown bits. Reuse the existing VFS capability
checks and EA safeguards.
Document append-only alongside immutable. Both flags now survive inode
reclaim and remount without changing the NTFS attribute format.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Add a fileattr setter for immutable and store its state in bit 0 of a
little-endian u32 in the private $LINUXFLAGS EA. Reuse the standard NTFS
EA attributes and restore the flag when loading an inode, so eviction
and unmount do not discard the setting.
Use $LINUXFLAGS to avoid the WSL-owned $LX namespace.
Preserve unknown bits and delete the entry only when the entire value is
zero. Reject malformed values with EUCLEAN. Reject direct xattr writes
and removal to avoid bypassing fileattr permissions or stale cached
state. Update the cached flags only after the EA update succeeds.
Reject clearing immutable on system metadata files and files protected
by sys_immutable, following inode-load policy. Do not persist a bit
derived solely from this policy. Preserve append state without allowing
it to be changed at this stage. Compression, encryption and mount-wide
case folding remain read-only. Document the format and its Linux-only
enforcement.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Add fileattr_get operations for files and directories, as well as the
existing symlink and special inode operation tables. Report compression,
encryption, immutable and append-only from cached inode state, and
FS_CASEFOLD_FL from the mount-wide case sensitivity policy.
This introduces querying only. It neither reads a private flag EA nor
allows userspace to change the reported flags.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Creating or replacing an EA can leave EA data and information out of
sync if a later update fails. Existing deletion rollback ignores its own
errors, and creation changes metadata before preparing the new list.
Prepare the complete new list while retaining both original attributes.
Update EA data and information only after preparation succeeds, restore
both on failure, and publish the cached presence state only on success.
Keep structure errors as EUCLEAN and preserve operation errors. Mark the
volume erroneous and shut it down if either restoration fails.
This handles synchronous failures; it does not make the two updates
atomic across power loss or guarantee restoration on a failing device.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The EA setter identifies removal using a zero value length together with
XATTR_REPLACE. A replacement with a valid empty value is therefore
mistaken for deletion.
Use a NULL value to identify removal and keep zero-length values valid.
Reject removal or XATTR_REPLACE for an absent entry before creating
metadata, including when the file has no EA attributes.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_attr_exist() treats lookup failures as absence. Using it while
updating EAs can select creation or removal paths after an allocation or
I/O failure.
Use an EA-local lookup helper that preserves errors from mapping the MFT
record, allocating the search context and looking up the attribute.
Check both EA attributes before modifying either and return EUCLEAN if
only one exists. Keep the known presence state for the final update.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_write_ea() replaces negative write errors with EIO and ignores
errors when shrinking the attribute after writing a shorter list. This
can report success even though the final resize failed.
Preserve negative write errors, use EIO for short writes, and return
truncate failures to the caller.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
A zero next-entry offset terminates an EA list. Appending an entry
without linking the old tail makes the new entry unreachable. Invalid
entries are also treated as missing names, allowing setters to proceed
on corrupt metadata.
Validate the entire chain before modifying it and connect a zero tail to
the append position. Check name terminators and retain the full tail
span when removing an entry. Return EUCLEAN for malformed EA structures
and inconsistent information lengths, preserving that error through the
get, set and list paths. Keep ENOENT for a missing name and translate it
to ENODATA only at the xattr read boundary. Preserve lower-level read
errors.
Reuse the same full-chain validation in ntfs_listxattr(), including
size-only queries, before copying names. Reject malformed lists with
EUCLEAN instead of returning an empty or partial list.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The successful EA update path tests ea_info_qsize when updating
NInoHasEA, but this size excludes the appended entry. Creating the first
EA, or replacing the only entry, can therefore clear the cached presence
flag despite a successful update. Reads then return ENODATA until
reload.
Include the appended entry in the size used for the presence test.
Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Add an optional Windows-style pathname interface for named $DATA streams,
enabled with streams_interface=windows. The option defaults to none, and
the named-stream ioctls remain available regardless of this setting.
Support lookup, creation, and removal of named streams for existing regular
files and directories. A stream is opened as a regular file through the
base-name and stream-name form in the final path component. A stream can be
created only for an existing file or directory. The pathname interface
accepts a base file name and stream name only. It rejects paths that also
specify an NTFS attribute type such as $DATA. In windows mode, ordinary
filenames containing a colon are hidden from directory listings and cannot
be accessed through the pathname interface.
Match stream names case-insensitively. Streams and their base objects
report the same inode number. Removing the base object while a stream is
open detaches the stream from the namespace. Since NTFS has no orphan-stream
list, a crash can leave the stream data unreachable on disk.
Expose named streams as regular file descriptors for the file operations
requested by Wine, including read, write, fsync, fdatasync,
sync_file_range, file locking, mmap, futimes, fstat, ftruncate, SEEK_DATA,
SEEK_HOLE, fallocate, and pathname unlink. Stream timestamps are shared
with the base file. fstat reports the base metadata and inode number with
the stream's own size and allocation.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
NTFS supports multiple named $DATA attributes, commonly known as alternate
data streams. Add NTFS-specific ioctls to list, read, write, and remove
named streams through an opened base file or directory.
The UAPI provides separate commands for each operation.
- NTFS_IOC_STREAM_READ
- NTFS_IOC_STREAM_WRITE
- NTFS_IOC_STREAM_REMOVE
- NTFS_IOC_LIST_STREAMS
Read and write requests use struct ntfs_stream to specify the stream name,
byte offset, and transfer length. Writes create the stream if it does not
already exist. A write failure after creation may leave the new stream
visible. It is not rolled back because another caller may already have
opened it. Userspace can remove it with NTFS_IOC_STREAM_REMOVE.
The list command returns variable-length entries containing each named
stream's data size, allocated size, and name. If the buffer is too small,
the command returns -ENOSPC without copying entries. bytes_returned reports
the required buffer size, and stream_count reports the number of streams.
Stream names use the mounted filesystem NLS by default. Set
NTFS_STREAM_FL_UTF16 to pass or receive raw UTF-16LE names. In NLS mode,
names that cannot be represented by the mounted character set are omitted
from the list. Use UTF-16 mode for lossless enumeration. Read and write
transfers are limited to 16 MiB per request.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Propagate errors from truncating an EA stream so callers do not
report a successful xattr update after a failed resize.
Fixes: fc053f05ca28 ("ntfs: add reparse and ea operations")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
iomap_zero_range() skips holes, so EOF-polluted cache data can survive
gap zeroing. Discard the uninitialized cache range before advancing
initialized_size so later reads cannot expose stale bytes.
Perform the cleanup in ntfs_extend_initialized_size() so both file writes
and shared writable mmap preparation use it. Hold the invalidate lock
while reading initialized_size, clearing the cache, zeroing the gap, and
updating the attribute. Release the lock on every exit path.
Fixes: af0db57d4293 ("ntfs: update inode operations")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Internal attribute truncation bypasses truncate_setsize(), so successful
resizes must update the attribute inode's i_size. Restrict the update to
attribute inodes to keep KEEP_SIZE fallocate from changing a file's i_size.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The NTFS put_folio callbacks clear uninitialized data around buffered
writes and zero ranges. Move this work to iomap block preparation and
use the default folio release path.
Set IOMAP_F_ZERO_TAIL only for mapped writes and zero ranges starting
at or beyond initialized_size. Split mapped ranges at initialized_size
and use iomap_truncate_page() to clear the boundary block's uninitialized
tail when a mapping includes initialized bytes in that block. This
preserves valid data when a short copy retries with a smaller length
inside a cached iomap. Apply this to buffered write mappings and the
read mappings reused by iomap_zero_range().
Record initialized_size in the validity cookie and revalidate it after
locking each folio. Skip bytes initialized since the tail range was
selected to preserve data written through a concurrent shared mapping.
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The cluster allocator only consults $Bitmap and never loads
$BadClus:$Bad. A free bitmap bit for a known bad cluster can therefore
place that cluster in the free-space cache and make it available for
new file allocations.
Load the named nonresident $Bad stream and map every attribute extent
before validating full-volume coverage and identity mappings for bad
runs. Reserve only free bits in $Bitmap on writable mounts and flush
the corrections before the initial free-space scan. Keep bad-cluster
counts diagnostic so reservations are accounted for exactly once.
Force read-only mounts with repair advice when $Bad cannot be loaded
or validated, and prevent read-write remounts after such errors. Leave
the bitmap unchanged on read-only mounts and fail mounts on memory
allocation failure. Suppress errors=panic while loading $BadClus so
damaged metadata can fall back to read-only.
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The attribute validator required the compressed_size field for
every sparse or compressed extent. Continuation extents omit that field,
so their valid mapping_pairs_offset of 64 was rejected and compressed
reads failed.
Fixes: ffc755828de1 ("ntfs: Fix min_len for compressed/sparse attributes in ntfs_non_resident_attr_value_is_valid()")
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_check_logfile() calls kmap_local_folio() on every iteration of its
search loop but kunmap_local() only once per folio. The loop visits
positions 0, 512, 1024, 2048, 4096 and so on. With 4 KiB pages the first
four are in one page, so a mount whose first LogFile folio is in highmem
leaves three entries on the kmap_local stack of the mounting task.
Kernels without HIGHMEM are not affected.
The leaked entries keep migration disabled. nr_pinned of the runqueue
the mount ran on stays raised after the task exits, so taking that CPU
offline blocks forever in balance_hotplug_wait().
The fifth mount in one task reaches KM_MAX_IDX (12 leaked entries plus
4 in the loop) and hits the BUG_ON() in kmap_local_idx_push():
kernel BUG at mm/highmem.c:480!
On x86-32 the generic entry code also warns on return to user space:
DEBUG_LOCKS_WARN_ON(current->kmap_ctrl.idx)
WARNING: include/linux/highmem-internal.h:17 at __do_fast_syscall_32+0x21e/0x550
Map each page once, when it is read, and unmap that address.
Fixes: 5218cd102aec ("ntfs: update misc operations")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
check_mft_mirror() compares the mft records of a page with the mirror
records by advancing kmft and kmirr by the record size for every record.
It then passes the advanced pointers to kunmap_local(). After the last
record of a page they point one page past the mapping.
With HIGHMEM kunmap_local() warns that the address does not match the
top of the kmap_local stack. What it does next depends on how the
architecture finds the page table entry:
- 32-bit ARM looks the entry up by that address. It clears the entry of
the neighbouring fixmap slot and leaves the real mapping in place.
The next kmap_local() on that CPU that reaches the slot hits the
BUG_ON(!pte_none()) in __kmap_local_pfn_prot().
- x86-32 takes the entry from the stack index, so the wrong address
does not select a wrong entry. In QEMU the mount carried on after the
warning.
With 4 KiB pages and 1 KiB mft records the four mirror records fill
exactly one page, so every mount whose $MFT and $MFTMirr folios are in
highmem hits it. A fresh mkntfs volume on 32-bit ARM
(multi_v7_defconfig, 256 MiB of highmem) fails on the first mount:
WARNING: mm/highmem.c:623 at kunmap_local_indexed+0x254/0x26c, CPU#1: mount/85
kunmap_local_indexed from ntfs_fill_super+0x224c/0x35a0
ntfs_fill_super from get_tree_bdev_flags+0x1d8/0x2a4
ntfs: volume version 3.1, dev loop0, cluster size 4096
kernel BUG at mm/highmem.c:565!
PC is at __kmap_local_pfn_prot+0x210/0x214
__kmap_local_page_prot from ntfs_check_logfile+0x1fc/0x1210
Found with syzkaller. Kernels without HIGHMEM do not show it.
kmap_local_folio() returns the direct map address there and
kunmap_local() has no mapping to remove.
Keep the addresses returned by kmap_local_folio() and unmap with those.
Fixes: 6251f0b0de7d ("ntfs: update super block operations")
Cc: stable@vger.kernel.org
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
An asynchronous direct write can remain in flight after the inode lock is
released. If another direct write falls back to buffered I/O while the
first write is still pending, iomap_file_buffered_write() can dirty pages
before the first write completes its post-I/O page cache invalidation.
The invalidation then finds dirty pages, reports a page cache invalidation
failure, and records -EIO in the mapping error sequence. A later fsync()
therefore returns -EIO.
Commit 15cdefd0c0522f9d5e12d947fa04f4c11649b699 ("ext4: drain
in-flight DIO before buffered write fallback") fixed the same race in
ext4. NTFS has an equivalent fallback after iomap_dio_rw() returns
-ENOTBLK or a short write, but does not drain other in-flight DIO before
dirtying the page cache.
Wait for in-flight DIO before calling iomap_file_buffered_write() in the
fallback path. Since NTFS supports IOCB_NOWAIT, do not enter the blocking
fallback for such requests. Return -EAGAIN if no bytes were written, or
preserve the positive short-write result if the direct write made partial
progress.
A reproducer using concurrent AIO direct writes and buffered fallback
triggered the following warning and made a subsequent fsync() return
-EIO:
Page cache invalidation failure on direct I/O. Possible data corruption
due to collision with buffered I/O!
Fixes: 9c87959601e8 ("ntfs: update file operations")
Link: https://lore.kernel.org/r/20260629113827.4074335-3-libaokun@linux.alibaba.com
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Jiale Yao <yaojiale02@163.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_attr_map_cluster() asks ntfs_cluster_alloc() for contiguous
clusters and merges the whole result into the runlist, but reports only
its first run, so its callers zero only that run. Within a bitmap page
the allocator keeps such a request to one run, because a cluster in use
ends it. The zone search can also move on without testing the clusters
after the run, though: it skips a bitmap page that has no free clusters,
it goes from the end of the zone to the start of pass 2, and once every
zone has been searched it shrinks the MFT zone by half and goes on at
its new end. After each of these jumps the first cluster tested is
still taken as the next one of the run, and if it is free it starts a
second run elsewhere on the volume.
fallocate() over a hole then leaves the clusters of that second run
holding whatever they held before: on a nearly full volume, 16 of 20
fallocated clusters read back a deleted file's data, in each of the
three cases.
Delayed allocation gets a second run without punching any holes: filling
the same volume with write() reaches the last case when the MFT zone is
shrunk. The allocator then takes only the first run off the
dirty-cluster count, and after the fill statfs() reported no free space
while 939 clusters were still free, until the next mount.
Before setting the bit of a cluster for a contiguous request, check that
the cluster comes right after the run, and return the run as it is if
not; no bit has to be cleared. ntfs_attr_map_cluster() already handles
a short run, which a cluster in use produces in the same way: its
callers ask again for the rest.
Fixes: 11ccc9107dc4 ("ntfs: update runlist handling and cluster allocator")
Suggested-by: Namjae Jeon <linkinjeon@kernel.org>
Link: https://lore.kernel.org/all/CAKYAXd-agPFvDj2-HvjP3SLtG7AxkqUeNPqYyrLt-BN7fT8w6g@mail.gmail.com/
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_fallocate() fails with -ENOSPC whenever the MFT zone has shrunk to
nothing. The cluster allocator gives the MFT zone up when it cannot
find free clusters elsewhere, and nothing restores it before the next
mount, so after one such failure every fallocate() on the volume fails
with ENOSPC, punching holes included, however much space is freed. The
allocator failure fixed by the previous patch was enough to get there:
afterwards a one-cluster fallocate() failed with ENOSPC while 123 MiB of
the 128 MiB volume were free.
write() and truncate() do not look at the MFT zone, and
ntfs_allocate_range() already fails with -ENOSPC when too few clusters
are free. Remove the check.
Fixes: 9c87959601e8 ("ntfs: update file operations")
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
When ntfs_cluster_alloc() is given a start_lcn, it first tries the
clusters from there on. If that does not satisfy the request, it moves
on to the zone's current position, but keeps the pass, the zone_end and
the has_guess state it had. That loses free clusters in two ways. If
the search had already moved on to pass 2, whose range ends at the hint,
it scans only from the zone position to the hint and misses every free
cluster between the start of the zone and the zone position. If no
cluster had been tested yet, has_guess is still set, so the cluster at
the zone position is tried as if it had been the hint, and when that
cluster is in use the rest of the bitmap buffer is skipped.
Both happen when the hint lies at or past the end of the volume, which
ntfs_attr_map_cluster() produces when it extrapolates from the last
allocated run across a hole. The allocator then finds nothing, shrinks
the MFT zone to nothing trying to satisfy the request, and fails with
-ENOSPC.
To reproduce on a 128 MiB volume with 4 KiB clusters, extend two files
in turn by one cluster at a time, alternating between fallocate(),
write() past EOF and truncate() up, so that the runs of each file are
separated by holes. When the volume is full, truncate both files back
to 1 MiB and start again. During the second round a one-cluster
fallocate() fails with ENOSPC while 40 MiB is free.
Start the zone over as if no hint had been given. A contiguous request
can get there with the run from the hint already allocated, when that
run reached the end of a bitmap buffer or of the zone. Return that run
instead, as when a cluster in use ends it; going on at the zone position
gives the request a second run that its caller does not expect. That
could happen before this patch too, whenever the cluster at the zone
position was free. ntfs_attr_map_cluster() reports and zeroes only the
first run, so after a fallocate() of 20 clusters over a hole, with the
hint 4 clusters before the end of the volume, 16 of them read back the
data of a deleted file.
Fixes: 11ccc9107dc4 ("ntfs: update runlist handling and cluster allocator")
Suggested-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_attrlist_update_locked() resizes the attribute list and then, for
$MFT, tries to reserve the maximum list size. When that allocation
fails with -ENOSPC it falls back to ntfs_attrlist_repack(), which reads
the list through ntfs_inode_attr_pread(). The read stops at i_size,
but i_size is only updated after the reserve, so when the list has just
grown the repack gets a short read and returns -EIO. Only -ENOSPC from
the reserve is ignored, so the -EIO fails the $MFT extension and with
it the file creation that needed a new mft record.
On a 32 MiB volume with 512-byte clusters whose $MFT has a non-resident
attribute list, 591 of 1500 creations of empty files succeed and the
rest fail with EIO while 742 KiB is still free:
ntfs: (device vda): ntfs_attrlist_update_locked(): Failed to reserve attribute list space
ntfs: Failed add attr entry to attrlist
ntfs: MP update failed
ntfs: (device vda): ntfs_mft_record_alloc(): Failed to extend mft data allocation.
Update i_size as soon as the list has been resized. File creation then
goes on until the volume is full and fails with ENOSPC.
Fixes: b1d732e62a5b ("ntfs: repack $MFT/$ATTRIBUTE LIST")
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_mft_data_extend_allocation_nolock() drops the $MFT runlist lock
before allocating clusters, and every path into undo_alloc arrives
without it, except a map_mft_record() failure, which takes it first.
undo_alloc never releases it, so the lock leaks and the next $MFT
extension and $MFT writeback hang. The restore_undo_alloc failure
path, on the other hand, releases the lock without holding it. And
undo_alloc frees the clusters with ntfs_cluster_free() and truncates
the runlist without the lock, although both require it.
Enter undo_alloc without the lock on every path. Merge the new clusters
with ntfs_runlists_merge_keep_src() and keep the runlist that
ntfs_cluster_alloc() returned until the extension is complete. On
failure, undo_alloc truncates $MFT's runlist under the lock and, after
dropping it, frees the clusters from the kept runlist with
ntfs_cluster_free_from_rl(). That keeps lcnbmp_lock outside the runlist
lock, the order given by the comment before the cluster allocation.
Unlike ntfs_cluster_free() on a volume mounted with -o discard, this
does not issue discards for the clusters, which were never written; the
runlist merge failure path already frees them the same way. If the
truncation fails, the runlist may still reference the clusters, so they
stay allocated and the volume is marked for chkdsk; at this call site
the truncation only shrinks the runlist and cannot fail today.
A shorter fix would keep calling ntfs_cluster_free() on the live
runlist without the lock, relying on $MFT's runlist being fully mapped
and changed only by this function under mrec_lock. That breaks
ntfs_cluster_free()'s documented locking rule on an argument about the
rest of the driver, so this patch does not do that.
Fixes: 115380f9a2f9 ("ntfs: update mft operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_runlists_merge() frees the source runlist once its runs are in the
destination. A caller that may have to undo the merge then has to work
out its runs again from the merged runlist, where the first and the
last of them may have been coalesced with neighbouring runs.
Add ntfs_runlists_merge_keep_src(), which neither modifies nor frees
the source runlist. For that, ntfs_rl_append() and ntfs_rl_replace()
now merge the right-hand end into the copied run in the destination
instead of into the last source run before copying it, and the merge
helpers take the source as const, so the compiler checks that none of
them writes to it. The merged runlist is the same as before.
For every caller, a source runlist without any mapped run, which the
merge already warns about, now fails with -EINVAL instead of carrying
on with nothing to insert: with no run copied, the right-hand merge
into the destination would index before the insertion point.
The next patch uses ntfs_runlists_merge_keep_src() to free exactly the
clusters it allocated when it has to undo an $MFT data extension.
Suggested-by: Hyunchul Lee <hyc.lee@gmail.com>
Cc: stable@vger.kernel.org # needed by the next patch
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
When ntfs_mft_data_extend_allocation_nolock() fails after it has
rebuilt the mapping pairs of the last $MFT data extent, undo_alloc
truncates the runlist and then rebuilds the old mapping pairs from rl2,
a pointer into the runlist taken before the truncation.
ntfs_rl_truncate_nolock() can reallocate the runlist, and KASAN then
reports a use-after-free in ntfs_mapping_pairs_build().
Pass the start of the runlist instead, and hold the runlist lock for
reading while the mapping pairs are built from it.
ntfs_mapping_pairs_build() skips to the element containing the first
vcn by itself.
Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Cc: stable@vger.kernel.org
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_non_resident_attr_expand() changes ni->runlist.rl while it
allocates clusters: ntfs_attr_map_whole_runlist(), the compressed
branch's ntfs_rl_realloc() and ntfs_runlists_merge() can each kvfree()
the old array. Unless the caller already holds ni->runlist.lock, none
of this happens under it; only the rollback takes it. Callers without
it include the write path, fallocate, ntfs_inode_attr_pwrite() and
ntfs_resident_attr_resize().
Those callers hold mrec_lock, and the write path also inode_lock, but
the iomap read side takes neither: FIEMAP, page faults, readahead and
splice read reach ntfs_read_iomap_begin_non_resident(), which takes only
ni->runlist.lock. A FIEMAP running while write(2) extends the same file
can walk the array that ntfs_runlists_merge() has just freed:
BUG: KASAN: slab-use-after-free in ntfs_attr_vcn_to_rl+0x19b/0x200
A reader that finds a vcn unmapped in the stale array also maps it from
disk into the runlist the writer is changing, which shows up as "Run
lists overlap. Cannot merge!".
Take ni->runlist.lock for writing around the part of the expansion that
changes the runlist and allocated_size, up to and including the mapping
pairs update, as ntfs_non_resident_attr_shrink() does since commit
91709ba5d6d7 ("ntfs: protect runlist updates with the runlist lock"),
and hold it throughout the rollback, where ntfs_cluster_free() requires
it. The lock nests inside mrec_lock, as on the truncate-up path, which
already calls this function with the runlist lock held. Where the
caller says it holds the lock (locked_ni == ni), assert that it holds it
for writing.
For an $ATTRIBUTE_LIST whose lock the caller does not hold, drop the
lock again before the mapping pairs update: that update can resize the
same list through ntfs_attrlist_update_locked(), which returns -ENOSPC
when told that the list's lock is held. Holding it there made punching
holes into a large fragmented file fail with -ENOSPC.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_read_locked_inode(), ntfs_read_locked_attr_inode() and
ntfs_read_locked_index_inode() take a non-resident attribute's data_size
and initialized_size from disk without checking them against its
allocated_size. The runlist ends at allocated_size and the read path
maps what lies beyond it as a hole, so a data_size larger than the
allocation makes reads return zeros that are not on disk, with no error.
On a crafted volume with 4 KiB clusters where a 6144000-byte file claims
a data_size and initialized_size 64 KiB beyond its allocation, reading
the file returns 16 clusters of such zeros. A sparse file behaves the
same. A compressed file instead fails with -EIO after a burst of "Still
have pages left!" errors from ntfs_read_compressed_block().
Require 0 <= initialized_size <= data_size <= allocated_size, with
allocated_size a multiple of the cluster size, when the inode is read,
as fs/ntfs3 does in mi_enum_attr(), and fail with -EIO otherwise, which
marks the inode bad and the volume as having errors. initialized_size
above data_size is rejected too because an extending write zeroes the
gap it opens only from initialized_size onwards. An unaligned
allocated_size ends inside a cluster that the read path treats as past
the end: a crafted 66440-byte file with 4 KiB clusters reads its last
904 bytes as zeros.
Sparse and compressed attributes need no exception. Every non-resident
attribute has a cluster-aligned allocated_size >= data_size, holes
included, on eight public test volumes (seven written by Windows, with
LZNT1-compressed files, a sparse $UsnJrnl:$J and a OneDrive placeholder
whose unnamed $DATA is one hole, and one by mkntfs), on a volume written
by ntfs-3g and on one written by this driver, and the patched driver
reads every file on them as before. fs/ntfs3 has enforced the same
checks since v6.6, also without exceptions. The layout.h comment saying
that data_size can exceed allocated_size for compressed and sparse
attributes is corrected.
This also covers a non-resident attribute list, which
load_attribute_list() reads through ntfs_attr_iget(), and $MFT, whose
inode goes through ntfs_read_locked_inode() after the previous patch's
check. $MFT's own non-resident attribute list goes through neither:
ntfs_read_inode_mount() loads it with load_attribute_list_mount() and
ntfs_read_locked_inode() skips it for $MFT, so the check is added there
too. The check was already missing in the classic driver; the Fixes
tag names the commit that brought that code back.
Fixes: 1e9ea7e04472 ("Revert "fs: Remove NTFS classic"")
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_read_inode_mount() takes $MFT's i_size from data_size without
checking it against allocated_size, unlike the resident case in
ntfs_read_locked_inode(). mft records between the two are not on disk.
On a crafted volume with 512-byte clusters whose $MFT is cut to 4
clusters while data_size still says 27 records, reading the folio
holding records 0-3 finds the end of the runlist at vcn 4. An unpatched
kernel hangs there on the folio lock, as in "ntfs: fail the mount when
$MFT needs its own extent records". With the previous patch vcn 4-7 are
past the allocation and so read as a hole: records 2 and 3 come back as
zeros and the mount carries on until check_mft_mirror() finds the zeroed
record 2.
Refuse such a $MFT before anything is read through it. The mount now
fails with:
ntfs: (device vda): ntfs_read_inode_mount(): $MFT data size 27648
exceeds its allocated size 2048. $MFT is corrupt. Run chkdsk.
fs/ntfs3 rejects any non-resident attribute whose data_size exceeds its
allocated size. This patch checks only $MFT; the next one covers the
other non-resident attributes.
Fixes: b041ca562526 ("ntfs: update iomap and address space operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_attr_vcn_to_rl() retries ntfs_map_runlist_nolock() for any lcn up
to LCN_RL_NOT_MAPPED, which includes LCN_ENOENT, but turns a failed
retry into an error only for LCN_RL_NOT_MAPPED. For LCN_ENOENT the
error is dropped and the read path maps the range as a hole.
An LCN_ENOENT below allocated_size comes from a base extent with a
highest_vcn of 0, which ntfs_mapping_pairs_decompress() takes to map the
whole attribute, so the runlist ends after its last mapping pair. If
the pairs end early, the retry finds the same extent and fails with
-ENOENT. On a crafted volume with 4 KiB clusters, a 64-cluster file
whose mapping pairs stop after 16 clusters reads 48 clusters of zeros,
with no error.
The same layout gets a crafted $MFT past the check from "ntfs: fail the
mount when $MFT needs its own extent records". With 512-byte clusters
and $MFT's mapping pairs ending at vcn 4, an unpatched kernel hangs on
the folio lock reading records 0-3. With the check alone, the -EIO is
dropped, records 2 and 3 read as zeros and the mount carries on until
check_mft_mirror() finds the zeroed record 2.
Fail the lookup whenever the retry leaves @vcn unmapped below
allocated_size, -ENOENT included. At or beyond allocated_size the end
of the runlist is still returned as it is.
A failed expansion in ntfs_non_resident_attr_expand() or
ntfs_attrlist_repack() truncates the runlist under the runlist lock but
restores allocated_size only after dropping it. A lookup in between
would now fail, so restore allocated_size before dropping the lock in
both, under size_lock, which ntfs_attr_vcn_to_rl() takes to read it.
The crafted file now fails from vcn 16 on with -EIO, and the crafted
volume fails to mount with the check's message.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Mounting a crafted image hangs the mount process forever, unkillable at
0% CPU. Only the hung-task detector reports it:
INFO: task mount:74 blocked in I/O wait for more than 30 seconds.
folio_wait_bit_common <- waits forever
filemap_read_folio
map_mft_record_folio
map_mft_record
ntfs_map_runlist_nolock
ntfs_attr_vcn_to_rl
__ntfs_read_iomap_begin
iomap_read_folio
ntfs_read_folio <- already holds that folio's lock
ntfs_read_inode_mount
ntfs_fill_super
ntfs_read_inode_mount() assembles $MFT's runlist one $DATA extent at a
time, hoping, as its comment says, that it never needs a part of $MFT it
has not decoded yet. If $MFT's attribute list puts one of its
attributes or later $DATA extents in an extent record outside the
runlist decoded so far, reading that record re-enters
ntfs_map_runlist_nolock() for $MFT. Depending on the layout, that waits
on the folio lock it already holds, as above, blocks on $MFT's runlist
lock, or dereferences NULL in map_extent_mft_record().
Mark the volume for the whole $DATA enumeration and have
ntfs_map_runlist_nolock() refuse $MFT with -EIO while the mark is set.
The enumeration decodes each extent itself with
ntfs_mapping_pairs_decompress(), so it does not need that path.
A validly placed record can trip the check too. The driver puts an
extent record for $MFT's own mapping pairs before the first vcn it
describes, but with clusters smaller than a page, the folio holding it
can still run past the decoded runlist. An unpatched kernel hangs on
that layout as well; with the check the mount fails. The check then
refuses only the folio's tail, so this patch needs "ntfs: do not map an
unmappable runlist fragment as a hole": without it the tail is
zero-filled and the mount serves an all-zero mft record. The mount now
fails instead of hanging:
ntfs: (device vda): ntfs_map_runlist_nolock(): $MFT needs its own
extent records to describe itself; cannot mount.
Tested under qemu with KASAN, PROVE_LOCKING and the hung-task detector
on ntfs-next, with and without the whole series: six crafted images
that hang or crash an unpatched kernel fail to mount with the series,
and nine images that mount without it still mount, three of them with
the same file listing and contents, among them a volume written by
ntfs-3g whose $MFT has its $DATA in three extent records.
Fixes: b041ca562526 ("ntfs: update iomap and address space operations")
Suggested-by: Hyunchul Lee <hyc.lee@gmail.com>
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
ntfs_write_simple_iomap_begin_non_resident() has the same unchecked
retry. LCN_RL_NOT_MAPPED passes its "lcn <= LCN_HOLE" test, so a
buffered write into a range whose extent record cannot be read is
merged into the runlist as LCN_DELALLOC over clusters that are already
allocated on disk, and write() succeeds. If the record stays
unreadable, writeback fails too and the data never reaches the disk;
the error only shows up at a later fsync() or a synchronous write.
On the volume from the previous patch, after a read of the file, an
8 KiB pwrite() at vcn 1000 returns 8192, fsync() returns -EIO, and
after remount the range is unchanged.
Fail the lookup here too, with -ENOMEM or -EIO. That pwrite() now
fails with -EIO. Writes whose range can be mapped are unaffected.
Fixes: b041ca562526 ("ntfs: update iomap and address space operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
When the extent mft record holding part of a file's runlist cannot be
read, ntfs_attr_vcn_to_rl() ignores the failed ntfs_map_runlist_nolock()
retry and returns with *lcn == LCN_RL_NOT_MAPPED. The iomap read path
only rejects lcn < LCN_ENOENT, so it maps the range as a hole and read()
returns zeros with no error. The first read already does this:
ntfs_attr_map_whole_runlist() keeps the fragments it could read,
readahead drops its error, and the next lookup finds the unmapped tail.
On a file whose runlist is split between its base record (vcn 0-214) and
one extent record (vcn 215-1499), breaking only the extent record's FILE
magic makes the kernel log "Failed to map extent mft record", yet read()
returns 1285 clusters of zeros for vcn 215-1499. A damaged attribute
list entry, which makes the retry fail with -ENOENT, gives the same
zeros.
Return -ENOMEM if the retry ran out of memory and -EIO otherwise. Both
callers already handle an ERR_PTR; other negative lcns, including
LCN_ENOENT, are returned as before, and so is LCN_RL_NOT_MAPPED at or
beyond allocated_size, where nothing is mapped: the runlist ends there
with LCN_RL_NOT_MAPPED when only the last extent is mapped, as after a
write into it, and with clusters smaller than a page every read of a
file's last folio looks up such vcns.
Reads of vcn 215-1499 now fail with -EIO. An intact volume exercised
with buffered, mmap and O_DIRECT I/O, fallocate, truncate, sparse and
compressed files behaves as before.
Fixes: 495e90fa3348 ("ntfs: update attrib operations")
Cc: stable@vger.kernel.org
Signed-off-by: Matthias Goergens <matthias.goergens@gmail.com>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Windows native sparse-file inspection shows that a non-resident $DATA
attribute can be marked sparse and record the standard compression unit
(4) even when the file is not compressed.
Fixes: af0db57d4293 ("ntfs: update inode operations")
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
Windows directory symlinks and junctions can carry
FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT in their entry while the reparse
flag is stored only in. The old directory enumeration path treated such
entries as DT_DIR, allowing no-follow userspace scanners to recurse
through symlink targets.
Fixes: 0a8ac0c1fa0b ("ntfs: update directory operations")
Signed-off-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
The MFT bitmap extension fast path sets $Bitmap directly, bypassing
ntfs_cluster_alloc() and its free_clusters and lcn_empty_bits_per_page
updates. Successful extensions overreport free space, and rollback adds
back counts that were never deducted.
Update both counts under lcnbmp_lock and the bitmap folio lock. Require
a nonzero page count and space remaining after delayed-allocation
reservations; otherwise use the regular allocator. The page check also
prevents underflow when the initial scan recorded zero after a read error.
Fixes: 6251f0b0de7d ("ntfs: update super block operations")
Suggested-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Xuewen Wang <wangxuewen@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|
|
If MFT bitmap extension fails before the initial $Bitmap scan completes,
rollback calls ntfs_bitmap_clear_bit(), which holds a folio lock while
ntfs_set_lcn_empty_bits() waits for the scan. The scanner deadlocks if it
still needs that folio.
Wait for the initial scan before taking the runlist or bitmap folio locks
and attempting allocation.
Fixes: 11ccc9107dc4 ("ntfs: update runlist handling and cluster allocator")
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Xuewen Wang <wangxuewen@kylinos.cn>
Reviewed-by: Baolin Liu <liubaolin@kylinos.cn>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
|