Skip to content

Commit a6d7636

Browse files
Dave Chinnerdchinner
authored andcommitted
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: Dave Chinner <[email protected]> Tested-by: Ross Zwisler <[email protected]> Signed-off-by: Dave Chinner <[email protected]>
1 parent 3b0fe47 commit a6d7636

File tree

1 file changed

+16
-9
lines changed

1 file changed

+16
-9
lines changed

fs/xfs/xfs_file.c

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -402,19 +402,26 @@ xfs_file_splice_read(
402402
if (XFS_FORCED_SHUTDOWN(ip->i_mount))
403403
return -EIO;
404404

405-
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
406-
407405
trace_xfs_file_splice_read(ip, count, *ppos, ioflags);
408406

409-
/* for dax, we need to avoid the page cache */
410-
if (IS_DAX(VFS_I(ip)))
411-
ret = default_file_splice_read(infilp, ppos, pipe, count, flags);
412-
else
413-
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
414-
if (ret > 0)
415-
XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
407+
/*
408+
* DAX inodes cannot ues the page cache for splice, so we have to push
409+
* them through the VFS IO path. This means it goes through
410+
* ->read_iter, which for us takes the XFS_IOLOCK_SHARED. Hence we
411+
* cannot lock the splice operation at this level for DAX inodes.
412+
*/
413+
if (IS_DAX(VFS_I(ip))) {
414+
ret = default_file_splice_read(infilp, ppos, pipe, count,
415+
flags);
416+
goto out;
417+
}
416418

419+
xfs_rw_ilock(ip, XFS_IOLOCK_SHARED);
420+
ret = generic_file_splice_read(infilp, ppos, pipe, count, flags);
417421
xfs_rw_iunlock(ip, XFS_IOLOCK_SHARED);
422+
out:
423+
if (ret > 0)
424+
XFS_STATS_ADD(ip->i_mount, xs_read_bytes, ret);
418425
return ret;
419426
}
420427

0 commit comments

Comments
 (0)