|
@@ -317,7 +317,19 @@ xfs_file_aio_read(
|
|
|
if (XFS_FORCED_SHUTDOWN(mp))
|
|
|
return -EIO;
|
|
|
|
|
|
- if (unlikely(ioflags & IO_ISDIRECT)) {
|
|
|
+ /*
|
|
|
+ * Locking is a bit tricky here. If we take an exclusive lock
|
|
|
+ * for direct IO, we effectively serialise all new concurrent
|
|
|
+ * read IO to this file and block it behind IO that is currently in
|
|
|
+ * progress because IO in progress holds the IO lock shared. We only
|
|
|
+ * need to hold the lock exclusive to blow away the page cache, so
|
|
|
+ * only take lock exclusively if the page cache needs invalidation.
|
|
|
+ * This allows the normal direct IO case of no page cache pages to
|
|
|
+ * proceeed concurrently without serialisation.
|
|
|
+ */
|
|
|
+ xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
|
|
|
+ if ((ioflags & IO_ISDIRECT) && inode->i_mapping->nrpages) {
|
|
|
+ xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
|
|
|
xfs_rw_ilock(ip, XFS_IOLOCK_EXCL);
|
|
|
|
|
|
if (inode->i_mapping->nrpages) {
|
|
@@ -330,8 +342,7 @@ xfs_file_aio_read(
|
|
|
}
|
|
|
}
|
|
|
xfs_rw_ilock_demote(ip, XFS_IOLOCK_EXCL);
|
|
|
- } else
|
|
|
- xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
|
|
|
+ }
|
|
|
|
|
|
trace_xfs_file_read(ip, size, iocb->ki_pos, ioflags);
|
|
|
|