Call splice_from_pipe directly from XFS so that we can do our normal I/O path locking. This fixes a rare to hit deadlock vs direct I/O as reported by Dave Chinner long time ago. Signed-off-by: Christoph Hellwig <hch@xxxxxx> --- fs/xfs/xfs_file.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 52c91e1..9d0da98 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -43,6 +43,7 @@ #include <linux/dcache.h> #include <linux/falloc.h> #include <linux/pagevec.h> +#include <linux/splice.h> static const struct vm_operations_struct xfs_file_vm_ops; @@ -348,14 +349,6 @@ xfs_file_splice_read( return ret; } -/* - * xfs_file_splice_write() does not use xfs_rw_ilock() because - * generic_file_splice_write() takes the i_mutex itself. This, in theory, - * couuld cause lock inversions between the aio_write path and the splice path - * if someone is doing concurrent splice(2) based writes and write(2) based - * writes to the same inode. The only real way to fix this is to re-implement - * the generic code here with correct locking orders. - */ STATIC ssize_t xfs_file_splice_write( struct pipe_inode_info *pipe, @@ -377,15 +370,22 @@ xfs_file_splice_write( if (XFS_FORCED_SHUTDOWN(ip->i_mount)) return -EIO; - xfs_ilock(ip, XFS_IOLOCK_EXCL); - + xfs_rw_ilock(ip, XFS_IOLOCK_EXCL); trace_xfs_file_splice_write(ip, count, *ppos, ioflags); + ret = splice_from_pipe(pipe, outfilp, ppos, count, flags, pipe_to_file); + xfs_rw_iunlock(ip, XFS_IOLOCK_EXCL); + + if (ret > 0) { + int err; - ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); - if (ret > 0) XFS_STATS_ADD(xs_write_bytes, ret); - xfs_iunlock(ip, XFS_IOLOCK_EXCL); + err = generic_write_sync(outfilp, *ppos, ret); + if (err) + return err; + *ppos += ret; + } + return ret; } -- 1.7.10.4 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html