Handle non-data/hole seeks through generic_file_llseek_size() and return -ENXIO immediately when SEEK_DATA or SEEK_HOLE is requested at or past EOF. Handle compressed files in such cases properly as well. Signed-off-by: Konstantin Komarov --- fs/ntfs3/file.c | 14 ++++++++------ fs/ntfs3/frecord.c | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/fs/ntfs3/file.c b/fs/ntfs3/file.c index 06a5d9b44ac1..1b52447bd228 100644 --- a/fs/ntfs3/file.c +++ b/fs/ntfs3/file.c @@ -1008,7 +1008,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from) CLST lcn, clen; frame = valid >> frame_bits; - frame_vbo = valid & ~(frame_size - 1); + frame_vbo = valid & ~(u64)(frame_size - 1); off = valid & (frame_size - 1); err = attr_data_get_block(ni, frame << NTFS_LZNT_CUNIT, 1, &lcn, @@ -1077,7 +1077,7 @@ static ssize_t ntfs_compress_write(struct kiocb *iocb, struct iov_iter *from) if (bytes > count) bytes = count; - frame_vbo = pos & ~(frame_size - 1); + frame_vbo = pos & ~(u64)(frame_size - 1); index = frame_vbo >> PAGE_SHIFT; if (unlikely(fault_in_iov_iter_readable(from, bytes))) { @@ -1530,7 +1530,12 @@ static loff_t ntfs_llseek(struct file *file, loff_t offset, int whence) loff_t maxbytes = ntfs_get_maxbytes(ni); loff_t ret; - if (whence == SEEK_DATA || whence == SEEK_HOLE) { + if (whence != SEEK_DATA && whence != SEEK_HOLE) { + ret = generic_file_llseek_size(file, offset, whence, maxbytes, + i_size_read(inode)); + } else if ((unsigned long long)offset >= i_size_read(inode)) { + ret = -ENXIO; + } else { inode_lock_shared(inode); /* Scan file for hole or data. */ ret = ni_seek_data_or_hole(ni, offset, whence == SEEK_DATA); @@ -1538,9 +1543,6 @@ static loff_t ntfs_llseek(struct file *file, loff_t offset, int whence) if (ret >= 0) ret = vfs_setpos(file, ret, maxbytes); - } else { - ret = generic_file_llseek_size(file, offset, whence, maxbytes, - i_size_read(inode)); } return ret; } diff --git a/fs/ntfs3/frecord.c b/fs/ntfs3/frecord.c index 78eb065c7e43..4b5dd3de327b 100644 --- a/fs/ntfs3/frecord.c +++ b/fs/ntfs3/frecord.c @@ -2889,8 +2889,14 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data) * the file offset is set to offset. */ if (lcn != SPARSE_LCN) { - vbo = (u64)vcn << cluster_bits; - return max(vbo, offset); + /* Normal cluster. */ + break; + } + + if ((ni->std_fa & FILE_ATTRIBUTE_COMPRESSED) && + (vcn & (NTFS_LZNT_CLUSTERS - 1))) { + /* Compressed cluster in compressed frame. */ + break; } } else { /* @@ -2904,8 +2910,8 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data) /* native compression hole begins at aligned vcn. */ (!(ni->std_fa & FILE_ATTRIBUTE_COMPRESSED) || !(vcn & (NTFS_LZNT_CLUSTERS - 1)))) { - vbo = (u64)vcn << cluster_bits; - return max(vbo, offset); + /* Hole in sparsed or compressed file frame. */ + break; } } @@ -2914,6 +2920,9 @@ loff_t ni_seek_data_or_hole(struct ntfs_inode *ni, loff_t offset, bool data) return -EINVAL; } } + + vbo = (u64)vcn << cluster_bits; + return max(vbo, offset); } /* -- 2.43.0