Commit 0cefb29e authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner

xfs: using generic_file_direct_write() is unnecessary

generic_file_direct_write() does all sorts of things to make DIO
work "sorta ok" with mixed buffered IO workloads. We already do
most of this work in xfs_file_aio_dio_write() because of the locking
requirements, so there's only a couple of things it does for us.

The first thing is that it does a page cache invalidation after the
->direct_IO callout. This can easily be added to the XFS code.

The second thing it does is that if data was written, it updates the
iov_iter structure to reflect the data written, and then does EOF
size updates if necessary. For XFS, these EOF size updates are now
not necessary, as we do them safely and race-free in IO completion
context. That leaves just the iov_iter update, and that's also moved
to the XFS code.

Therefore we don't need to call generic_file_direct_write() and in
doing so remove redundant buffered writeback and page cache
invalidation calls from the DIO submission path. We also remove a
racy EOF size update, and make the DIO submission code in XFS much
easier to follow. Wins all round, really.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 40c63fbc
...@@ -659,6 +659,8 @@ xfs_file_dio_aio_write( ...@@ -659,6 +659,8 @@ xfs_file_dio_aio_write(
int iolock; int iolock;
size_t count = iov_iter_count(from); size_t count = iov_iter_count(from);
loff_t pos = iocb->ki_pos; loff_t pos = iocb->ki_pos;
loff_t end;
struct iov_iter data;
struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ? struct xfs_buftarg *target = XFS_IS_REALTIME_INODE(ip) ?
mp->m_rtdev_targp : mp->m_ddev_targp; mp->m_rtdev_targp : mp->m_ddev_targp;
...@@ -698,10 +700,11 @@ xfs_file_dio_aio_write( ...@@ -698,10 +700,11 @@ xfs_file_dio_aio_write(
if (ret) if (ret)
goto out; goto out;
iov_iter_truncate(from, count); iov_iter_truncate(from, count);
end = pos + count - 1;
if (mapping->nrpages) { if (mapping->nrpages) {
ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping, ret = filemap_write_and_wait_range(VFS_I(ip)->i_mapping,
pos, pos + count - 1); pos, end);
if (ret) if (ret)
goto out; goto out;
/* /*
...@@ -711,7 +714,7 @@ xfs_file_dio_aio_write( ...@@ -711,7 +714,7 @@ xfs_file_dio_aio_write(
*/ */
ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping, ret = invalidate_inode_pages2_range(VFS_I(ip)->i_mapping,
pos >> PAGE_CACHE_SHIFT, pos >> PAGE_CACHE_SHIFT,
(pos + count - 1) >> PAGE_CACHE_SHIFT); end >> PAGE_CACHE_SHIFT);
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
ret = 0; ret = 0;
} }
...@@ -728,8 +731,22 @@ xfs_file_dio_aio_write( ...@@ -728,8 +731,22 @@ xfs_file_dio_aio_write(
} }
trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0); trace_xfs_file_direct_write(ip, count, iocb->ki_pos, 0);
ret = generic_file_direct_write(iocb, from, pos);
data = *from;
ret = mapping->a_ops->direct_IO(WRITE, iocb, &data, pos);
/* see generic_file_direct_write() for why this is necessary */
if (mapping->nrpages) {
invalidate_inode_pages2_range(mapping,
pos >> PAGE_CACHE_SHIFT,
end >> PAGE_CACHE_SHIFT);
}
if (ret > 0) {
pos += ret;
iov_iter_advance(from, ret);
iocb->ki_pos = pos;
}
out: out:
xfs_rw_iunlock(ip, iolock); xfs_rw_iunlock(ip, iolock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment