Currently btrfs_direct_write() will not try to fault in the pages, but
directly fall back to buffered writes, if the first page of the buffer
can not be faulted in.
For example, during generic/362 with nodatasum mount option, there is a
write at file offset 0, length PAGE_SIZE, and the page is not faulted in.
Then we go the following callchain and directly fall back to buffered
IO:
btrfs_direct_write()
|- btrfs_dio_write()
|- __iomap_dio_rw()
| |- iomap_iter()
| | |- btrfs_dio_iomap_begin()
| | Now an ordered extent is allocated for the 4K write.
| |
| |- iomi.status = iomap_dio_iter()
| | Where iomap_dio_iter() returned -EFAULT.
| |
| |- ret = iomap_iter()
| | |- btrfs_dio_iomap_end()
| | | | return -ENOTBLK
| | |- return -ENOTBLK
| |- if (ret == -ENOTBLK) { ret = 0; }
| Now the return value is reset to 0.
|
|- ret = iomap_dio_complete()
| Since no byte is submitted, @ret is now zero.
|
|- if (iov_iter_count() > 0 && (ret == -EFAULT || ret > 0))
| @ret is zero, thus not meeting the above retry condition
|
|- Fallback to buffered
Just slightly loosen the condition to allow retry faulting in pages after
a zero sized short write.
Unlike the previous two bug fixes, this one is not really cause any real
bug, but only reducing the chance to do zero-copy direct IO.
Thus it doesn't really require stable-CC nor fixes-tag.
Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
if (ret > 0)
written = ret;
- if (iov_iter_count(from) > 0 && (ret == -EFAULT || ret > 0)) {
+ if (iov_iter_count(from) > 0 && (ret == -EFAULT || ret >= 0)) {
const size_t left = iov_iter_count(from);
/*
* We have more data left to write. Try to fault in as many as