diff options
Diffstat (limited to 'fs/xfs/xfs_file.c')
| -rw-r--r-- | fs/xfs/xfs_file.c | 27 | 
1 files changed, 17 insertions, 10 deletions
| diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 1f2e2845eb76..a7ceae90110e 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c @@ -529,18 +529,17 @@ xfs_file_dio_aio_write(  	count = iov_iter_count(from);  	/* -	 * If we are doing unaligned IO, wait for all other IO to drain, -	 * otherwise demote the lock if we had to take the exclusive lock -	 * for other reasons in xfs_file_aio_write_checks. +	 * If we are doing unaligned IO, we can't allow any other overlapping IO +	 * in-flight at the same time or we risk data corruption. Wait for all +	 * other IO to drain before we submit. If the IO is aligned, demote the +	 * iolock if we had to take the exclusive lock in +	 * xfs_file_aio_write_checks() for other reasons.  	 */  	if (unaligned_io) { -		/* If we are going to wait for other DIO to finish, bail */ -		if (iocb->ki_flags & IOCB_NOWAIT) { -			if (atomic_read(&inode->i_dio_count)) -				return -EAGAIN; -		} else { -			inode_dio_wait(inode); -		} +		/* unaligned dio always waits, bail */ +		if (iocb->ki_flags & IOCB_NOWAIT) +			return -EAGAIN; +		inode_dio_wait(inode);  	} else if (iolock == XFS_IOLOCK_EXCL) {  		xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);  		iolock = XFS_IOLOCK_SHARED; @@ -548,6 +547,14 @@ xfs_file_dio_aio_write(  	trace_xfs_file_direct_write(ip, count, iocb->ki_pos);  	ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io); + +	/* +	 * If unaligned, this is the only IO in-flight. If it has not yet +	 * completed, wait on it before we release the iolock to prevent +	 * subsequent overlapping IO. +	 */ +	if (ret == -EIOCBQUEUED && unaligned_io) +		inode_dio_wait(inode);  out:  	xfs_iunlock(ip, iolock); |