Commit a6d7636e authored by Dave Chinner's avatar Dave Chinner Committed by Dave Chinner

xfs: fix recursive splice read locking with DAX

Doing a splice read (generic/249) generates a lockdep splat because
we recursively lock the inode iolock in this path:

SyS_sendfile64
do_sendfile
do_splice_direct
splice_direct_to_actor
do_splice_to
xfs_file_splice_read			<<<<<< lock here
default_file_splice_read
vfs_readv
do_readv_writev
do_iter_readv_writev
xfs_file_read_iter			<<<<<< then here

The issue here is that for DAX inodes we need to avoid the page
cache path and hence simply push it into the normal read path.
Unfortunately, we can't tell down at xfs_file_read_iter() whether we
are being called from the splice path and hence we cannot avoid the
locking at this layer. Hence we simply have to drop the inode
locking at the higher splice layer for DAX.
Signed-off-by: default avatarDave Chinner <dchinner@redhat.com>
Tested-by: default avatarRoss Zwisler <ross.zwisler@linux.intel.com>
Signed-off-by: default avatarDave Chinner <david@fromorbit.com>
parent 3b0fe478
...@@ -402,19 +402,26 @@ xfs_file_splice_read( ...@@ -402,19 +402,26 @@ xfs_file_splice_read(
if (XFS_FORCED_SHUTDOWN(ip->i_mount)) if (XFS_FORCED_SHUTDOWN(ip->i_mount))
return -EIO; return -EIO;
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
trace_xfs_file_splice_read(ip, count, *ppos, ioflags); trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
/* for dax, we need to avoid the page cache */ /*
if (IS_DAX(VFS_I(ip))) * DAX inodes cannot ues the page cache for splice, so we have to push
ret = default_file_splice_read(infilp, ppos, pipe, count, flags); * them through the VFS IO path. This means it goes through
else * ->read_iter, which for us takes the XFS_IOLOCK_SHARED. Hence we
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); * cannot lock the splice operation at this level for DAX inodes.
if (ret > 0) */
XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret); if (IS_DAX(VFS_I(ip))) {
ret = default_file_splice_read(infilp, ppos, pipe, count,
flags);
goto out;
}
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED); xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
out:
if (ret > 0)
XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
return ret; return ret;
} }
......
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