@@ -31,6 +31,10 @@
#include <linux/fadvise.h>
static const struct vm_operations_struct xfs_file_vm_ops;
+STATIC ssize_t xfs_file_buffered_aio_write(struct kiocb *iocb,
+ struct iov_iter *from);
+STATIC ssize_t xfs_file_buffered_aio_read(struct kiocb *iocb,
+ struct iov_iter *to);
int
xfs_update_prealloc_flags(
@@ -169,6 +173,7 @@ xfs_file_dio_aio_read(
struct xfs_inode *ip = XFS_I(file_inode(iocb->ki_filp));
size_t count = iov_iter_count(to);
ssize_t ret;
+ ssize_t buffered_read = 0;
trace_xfs_file_direct_read(ip, count, iocb->ki_pos);
@@ -187,7 +192,13 @@ xfs_file_dio_aio_read(
is_sync_kiocb(iocb));
xfs_iunlock(ip, XFS_IOLOCK_SHARED);
- return ret;
+ if (ret < 0 || ret == count)
+ return ret;
+
+ iocb->ki_flags &= ~IOCB_DIRECT;
+ buffered_read = xfs_file_buffered_aio_read(iocb, to);
+
+ return ret + buffered_read;
}
static noinline ssize_t
@@ -483,6 +494,9 @@ xfs_file_dio_aio_write(
int iolock;
size_t count = iov_iter_count(from);
struct xfs_buftarg *target = xfs_inode_buftarg(ip);
+ loff_t offset, end;
+ ssize_t buffered_write = 0;
+ int err;
/* DIO must be aligned to device logical sector size */
if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
@@ -552,12 +566,25 @@ xfs_file_dio_aio_write(
out:
xfs_iunlock(ip, iolock);
- /*
- * No fallback to buffered IO on errors for XFS, direct IO will either
- * complete fully or fail.
- */
- ASSERT(ret < 0 || ret == count);
- return ret;
+ if (ret < 0 || ret == count)
+ return ret;
+
+ /* Fallback to buffered write */
+
+ offset = iocb->ki_pos;
+
+ buffered_write = xfs_file_buffered_aio_write(iocb, from);
+ if (buffered_write < 0)
+ return ret;
+
+ end = offset + buffered_write - 1;
+
+ err = filemap_write_and_wait_range(mapping, offset, end);
+ if (!err)
+ invalidate_mapping_pages(mapping, offset >> PAGE_SHIFT,
+ end >> PAGE_SHIFT);
+
+ return ret + buffered_write;
}
static noinline ssize_t