fs/iomap: Fix buffered write page prefaulting
authorAndreas Gruenbacher <agruenba@redhat.com>
Tue, 9 Nov 2021 11:56:06 +0000 (12:56 +0100)
committerAndreas Gruenbacher <agruenba@redhat.com>
Fri, 25 Mar 2022 14:14:03 +0000 (15:14 +0100)
When part of the user buffer passed to generic_perform_write() or
iomap_file_buffered_write() cannot be faulted in for reading, the entire
write currently fails.  The correct behavior would be to write all the
data that can be written, up to the point of failure.

Commit a6294593e8a1 ("iov_iter: Turn iov_iter_fault_in_readable into
fault_in_iov_iter_readable") gave us the information needed, so fix the
page prefaulting in generic_perform_write() and iomap_write_iter() to
only bail out when no pages could be faulted in.

We already factor in that pages that are faulted in may no longer be
resident by the time they are accessed.  Paging out pages has the same
effect as not faulting in those pages in the first place, so the code
can already deal with that.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
fs/iomap/buffered-io.c
mm/filemap.c

index 1753c26c8e76e300ff59c296d2b6b88d2b968db4..54516ab464cded06d4e574b431f453af41494408 100644 (file)
@@ -750,7 +750,7 @@ again:
                 * same page as we're writing to, without it being marked
                 * up-to-date.
                 */
-               if (unlikely(fault_in_iov_iter_readable(i, bytes))) {
+               if (unlikely(fault_in_iov_iter_readable(i, bytes) == bytes)) {
                        status = -EFAULT;
                        break;
                }
index daa0e23a6ee666b4fd7b7ab3b95ebd7ea156569e..76720226504845a9a88989bda732eaff9a4b60d5 100644 (file)
@@ -3743,7 +3743,7 @@ again:
                 * same page as we're writing to, without it being marked
                 * up-to-date.
                 */
-               if (unlikely(fault_in_iov_iter_readable(i, bytes))) {
+               if (unlikely(fault_in_iov_iter_readable(i, bytes) == bytes)) {
                        status = -EFAULT;
                        break;
                }