mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
hfsplus: fix issue of direct writes beyond end-of-file
The xfstests' test-case generic/729 fails with error: sudo ./check generic/729 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #36 SMP PREEMPT_DYNAMIC Fri Apr 17 12:40:51 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/729 23s ... [failed, exit status 1]- output mismatch mmap-rw-fault: /mnt/test/mmap-rw-fault.tmp: Input/output error The hfsplus_get_block() only allows creating the next sequential block. It returns -EIO for direct writes beyond EOF. This patch waits for any in-flight DIO on the inode to finish. Then, it extends the file by calling generic_cont_expand_simple() with the goal to guarantee that blockdev_direct_IO() finds all needed blocks already reachable sequentially. And, finally, it flushes and invalidates the DIO range again so the page cache is clean before the direct write begins. sudo ./check generic/729 FSTYP -- hfsplus PLATFORM -- Linux/x86_64 hfsplus-testing-0001 7.0.0-rc1+ #40 SMP PREEMPT_DYNAMIC Thu Apr 16 15:41:03 PDT 2026 MKFS_OPTIONS -- /dev/loop51 MOUNT_OPTIONS -- /dev/loop51 /mnt/scratch generic/729 23s ... 32s Ran: generic/729 Passed all 1 tests Closes: https://github.com/hfs-linux-kernel/hfs-linux-kernel/issues/210 cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de> cc: Yangtao Li <frank.li@vivo.com> cc: linux-fsdevel@vger.kernel.org Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com> Link: https://lore.kernel.org/r/20260417214940.2735557-2-slava@dubeyko.com Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
This commit is contained in:
parent
ca724ed2cb
commit
5f63ac80ae
|
|
@ -125,9 +125,44 @@ static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
struct file *file = iocb->ki_filp;
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
struct inode *inode = mapping->host;
|
||||
loff_t isize;
|
||||
size_t count = iov_iter_count(iter);
|
||||
loff_t end = iocb->ki_pos + count;
|
||||
ssize_t ret;
|
||||
|
||||
/*
|
||||
* The hfsplus_get_block() only allows creating the next sequential block.
|
||||
* For direct writes beyond EOF, expand the file first.
|
||||
*/
|
||||
if (iov_iter_rw(iter) == WRITE && iocb->ki_pos > i_size_read(inode)) {
|
||||
loff_t start_off, end_off;
|
||||
loff_t start_page, end_page;
|
||||
|
||||
isize = i_size_read(inode);
|
||||
|
||||
/*
|
||||
* Wait for any in-flight DIO on this inode to finish before
|
||||
* calling generic_cont_expand_simple().
|
||||
*/
|
||||
inode_dio_wait(inode);
|
||||
|
||||
ret = generic_cont_expand_simple(inode, iocb->ki_pos);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
start_off = isize;
|
||||
end_off = (end > 0) ? end - 1 : end;
|
||||
|
||||
ret = filemap_write_and_wait_range(mapping, start_off, end_off);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
start_page = start_off >> PAGE_SHIFT;
|
||||
end_page = end_off >> PAGE_SHIFT;
|
||||
|
||||
invalidate_inode_pages2_range(mapping, start_page, end_page);
|
||||
}
|
||||
|
||||
ret = blockdev_direct_IO(iocb, inode, iter, hfsplus_get_block);
|
||||
|
||||
/*
|
||||
|
|
@ -135,8 +170,7 @@ static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
|
|||
* blocks outside i_size. Trim these off again.
|
||||
*/
|
||||
if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) {
|
||||
loff_t isize = i_size_read(inode);
|
||||
loff_t end = iocb->ki_pos + count;
|
||||
isize = i_size_read(inode);
|
||||
|
||||
if (end > isize)
|
||||
hfsplus_write_failed(mapping, end);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user