Skip to content

Commit 2032a8a

Browse files
Brian Fosterdjwong
authored andcommitted
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>
1 parent ed79dac commit 2032a8a

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

fs/xfs/xfs_file.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -529,25 +529,32 @@ xfs_file_dio_aio_write(
529529
count = iov_iter_count(from);
530530

531531
/*
532-
* If we are doing unaligned IO, wait for all other IO to drain,
533-
* otherwise demote the lock if we had to take the exclusive lock
534-
* for other reasons in xfs_file_aio_write_checks.
532+
* If we are doing unaligned IO, we can't allow any other overlapping IO
533+
* in-flight at the same time or we risk data corruption. Wait for all
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.
535537
*/
536538
if (unaligned_io) {
537-
/* If we are going to wait for other DIO to finish, bail */
538-
if (iocb->ki_flags & IOCB_NOWAIT) {
539-
if (atomic_read(&inode->i_dio_count))
540-
return -EAGAIN;
541-
} else {
542-
inode_dio_wait(inode);
543-
}
539+
/* unaligned dio always waits, bail */
540+
if (iocb->ki_flags & IOCB_NOWAIT)
541+
return -EAGAIN;
542+
inode_dio_wait(inode);
544543
} else if (iolock == XFS_IOLOCK_EXCL) {
545544
xfs_ilock_demote(ip, XFS_IOLOCK_EXCL);
546545
iolock = XFS_IOLOCK_SHARED;
547546
}
548547

549548
trace_xfs_file_direct_write(ip, count, iocb->ki_pos);
550549
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);
551558
out:
552559
xfs_iunlock(ip, iolock);
553560

0 commit comments

Comments
 (0)