aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2019-03-25 20:01:45 -0400
committerDarrick J. Wong <darrick.wong@oracle.com>2019-03-26 11:37:55 -0400
commit2032a8a27b5cc0f578d37fa16fa2494b80a0d00a (patch)
tree327a39070ba431d137729e35407779e287eb5e11 /fs/xfs
parented79dac98c5e9f8471456afe2cc09a3912586b52 (diff)
xfs: serialize unaligned dio writes against all other dio writes
XFS applies more strict serialization constraints to unaligned direct writes to accommodate things like direct I/O layer zeroing, unwritten extent conversion, etc. Unaligned submissions acquire the exclusive iolock and wait for in-flight dio to complete to ensure multiple submissions do not race on the same block and cause data corruption. This generally works in the case of an aligned dio followed by an unaligned dio, but the serialization is lost if I/Os occur in the opposite order. If an unaligned write is submitted first and immediately followed by an overlapping, aligned write, the latter submits without the typical unaligned serialization barriers because there is no indication of an unaligned dio still in-flight. This can lead to unpredictable results. To provide proper unaligned dio serialization, require that such direct writes are always the only dio allowed in-flight at one time for a particular inode. We already acquire the exclusive iolock and drain pending dio before submitting the unaligned dio. Wait once more after the dio submission to hold the iolock across the I/O and prevent further submissions until the unaligned I/O completes. This is heavy handed, but consistent with the current pre-submission serialization for unaligned direct writes. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Allison Henderson <allison.henderson@oracle.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_file.c27
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(
529 count = iov_iter_count(from); 529 count = iov_iter_count(from);
530 530
531 /* 531 /*
532 * If we are doing unaligned IO, wait for all other IO to drain, 532 * If we are doing unaligned IO, we can't allow any other overlapping IO
533 * otherwise demote the lock if we had to take the exclusive lock 533 * in-flight at the same time or we risk data corruption. Wait for all
534 * for other reasons in xfs_file_aio_write_checks. 534 * other IO to drain before we submit. If the IO is aligned, demote the
535 * iolock if we had to take the exclusive lock in
536 * xfs_file_aio_write_checks() for other reasons.
535 */ 537 */
536 if (unaligned_io) { 538 if (unaligned_io) {
537 /* If we are going to wait for other DIO to finish, bail */ 539 /* unaligned dio always waits, bail */
538 if (iocb->ki_flags & IOCB_NOWAIT) { 540 if (iocb->ki_flags & IOCB_NOWAIT)
539 if (atomic_read(&inode->i_dio_count)) 541 return -EAGAIN;
540 return -EAGAIN; 542 inode_dio_wait(inode);
541 } else {
542 inode_dio_wait(inode);
543 }
544 } else if (iolock == XFS_IOLOCK_EXCL) { 543 } else if (iolock == XFS_IOLOCK_EXCL) {
545 xfs_ilock_demote(ip, XFS_IOLOCK_EXCL); 544 xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
546 iolock = XFS_IOLOCK_SHARED; 545 iolock = XFS_IOLOCK_SHARED;
@@ -548,6 +547,14 @@ xfs_file_dio_aio_write(
548 547
549 trace_xfs_file_direct_write(ip, count, iocb->ki_pos); 548 trace_xfs_file_direct_write(ip, count, iocb->ki_pos);
550 ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io); 549 ret = iomap_dio_rw(iocb, from, &xfs_iomap_ops, xfs_dio_write_end_io);
550
551 /*
552 * If unaligned, this is the only IO in-flight. If it has not yet
553 * completed, wait on it before we release the iolock to prevent
554 * subsequent overlapping IO.
555 */
556 if (ret == -EIOCBQUEUED && unaligned_io)
557 inode_dio_wait(inode);
551out: 558out:
552 xfs_iunlock(ip, iolock); 559 xfs_iunlock(ip, iolock);
553 560