diff mbox series

xfs: reflink should flush after an unaligned directio cow write

Message ID 20181121011706.GO6792@magnolia (mailing list archive)
State New, archived
Headers show
Series xfs: reflink should flush after an unaligned directio cow write | expand

Commit Message

Darrick J. Wong Nov. 21, 2018, 1:17 a.m. UTC
From: Darrick J. Wong <darrick.wong@oracle.com>

If userspace hands us a not-block-aligned directio write, we'll fall
back to a buffered write for the read-modify-write operation.
Unfortunately, we don't flush the page cache after a successful
fallback CoW, which means we break userspace's expectation that the data
has been sent to the drive.  Fix that by upgrading the iocb to DSYNC so
that the buffered CoW is synchronous.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
---
 fs/xfs/xfs_file.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

Comments

Christoph Hellwig Nov. 21, 2018, 4:30 p.m. UTC | #1
On Tue, Nov 20, 2018 at 05:17:06PM -0800, Darrick J. Wong wrote:
> From: Darrick J. Wong <darrick.wong@oracle.com>
> 
> If userspace hands us a not-block-aligned directio write, we'll fall
> back to a buffered write for the read-modify-write operation.
> Unfortunately, we don't flush the page cache after a successful
> fallback CoW, which means we break userspace's expectation that the data
> has been sent to the drive.

There is not such expectation.  Even with O_DIRECT you need an explicit
O_DSYNC to guarantee that.  Note that generic_file_direct_write doesn't
force O_DSYNC either.
diff mbox series

Patch

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index e47425071e65..675da7e9c001 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -692,6 +692,8 @@  xfs_file_write_iter(
 	struct xfs_inode	*ip = XFS_I(inode);
 	ssize_t			ret;
 	size_t			ocount = iov_iter_count(from);
+	bool			was_dsync = iocb->ki_flags & IOCB_DSYNC;
+	int			error;
 
 	XFS_STATS_INC(ip->i_mount, xs_write_calls);
 
@@ -714,9 +716,13 @@  xfs_file_write_iter(
 		ret = xfs_file_dio_aio_write(iocb, from);
 		if (ret != -EREMCHG)
 			return ret;
+		iocb->ki_flags |= IOCB_DSYNC;
 	}
 
-	return xfs_file_buffered_aio_write(iocb, from);
+	error = xfs_file_buffered_aio_write(iocb, from);
+	if (!was_dsync)
+		iocb->ki_flags &= ~IOCB_DSYNC;
+	return error;
 }
 
 static void