diff mbox series

[12/43] xfs: refine the unaligned check for always COW inodes in xfs_file_dio_write

Message ID 20241211085636.1380516-13-hch@lst.de (mailing list archive)
State New
Headers show
Series [01/43] xfs: constify feature checks | expand

Commit Message

Christoph Hellwig Dec. 11, 2024, 8:54 a.m. UTC
For always COW inodes we also must check the alignment of each individual
iovec segment, as they could end up with different I/Os due to the way
bio_iov_iter_get_pages works, and we'd then overwrite an already written
block.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/xfs/xfs_file.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

Comments

Darrick J. Wong Dec. 12, 2024, 9:44 p.m. UTC | #1
On Wed, Dec 11, 2024 at 09:54:37AM +0100, Christoph Hellwig wrote:
> For always COW inodes we also must check the alignment of each individual
> iovec segment, as they could end up with different I/Os due to the way
> bio_iov_iter_get_pages works, and we'd then overwrite an already written
> block.

I'm not sure why an alwayscow inode now needs to require fsblock-aligned
segments, seeing as it's been running mostly fine for years.

Is this a bug fix?  Or prep for rtzone files, which are (presumably)
always written out of place?

--D

> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  fs/xfs/xfs_file.c | 11 ++++++++++-
>  1 file changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
> index 2b6d4c71994d..6bcfd4c34a37 100644
> --- a/fs/xfs/xfs_file.c
> +++ b/fs/xfs/xfs_file.c
> @@ -721,7 +721,16 @@ xfs_file_dio_write(
>  	/* direct I/O must be aligned to device logical sector size */
>  	if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
>  		return -EINVAL;
> -	if ((iocb->ki_pos | count) & ip->i_mount->m_blockmask)
> +
> +	/*
> +	 * For always COW inodes we also must check the alignment of each
> +	 * individual iovec segment, as they could end up with different
> +	 * I/Os due to the way bio_iov_iter_get_pages works, and we'd
> +	 * then overwrite an already written block.
> +	 */
> +	if (((iocb->ki_pos | count) & ip->i_mount->m_blockmask) ||
> +	    (xfs_is_always_cow_inode(ip) &&
> +	     (iov_iter_alignment(from) & ip->i_mount->m_blockmask)))
>  		return xfs_file_dio_write_unaligned(ip, iocb, from);
>  	return xfs_file_dio_write_aligned(ip, iocb, from);
>  }
> -- 
> 2.45.2
> 
>
Christoph Hellwig Dec. 13, 2024, 5:14 a.m. UTC | #2
On Thu, Dec 12, 2024 at 01:44:42PM -0800, Darrick J. Wong wrote:
> On Wed, Dec 11, 2024 at 09:54:37AM +0100, Christoph Hellwig wrote:
> > For always COW inodes we also must check the alignment of each individual
> > iovec segment, as they could end up with different I/Os due to the way
> > bio_iov_iter_get_pages works, and we'd then overwrite an already written
> > block.
> 
> I'm not sure why an alwayscow inode now needs to require fsblock-aligned
> segments, seeing as it's been running mostly fine for years.

Because the storage you test always_cow on doesn't actually force
always_cow on you :)  I.e. these segmented iovecs can end up overwriting
a block.  That's ok if you're on a conventional device, but it will
error out on a sequential write required zoned.
Darrick J. Wong Dec. 13, 2024, 11:14 p.m. UTC | #3
On Fri, Dec 13, 2024 at 06:14:00AM +0100, Christoph Hellwig wrote:
> On Thu, Dec 12, 2024 at 01:44:42PM -0800, Darrick J. Wong wrote:
> > On Wed, Dec 11, 2024 at 09:54:37AM +0100, Christoph Hellwig wrote:
> > > For always COW inodes we also must check the alignment of each individual
> > > iovec segment, as they could end up with different I/Os due to the way
> > > bio_iov_iter_get_pages works, and we'd then overwrite an already written
> > > block.
> > 
> > I'm not sure why an alwayscow inode now needs to require fsblock-aligned
> > segments, seeing as it's been running mostly fine for years.
> 
> Because the storage you test always_cow on doesn't actually force
> always_cow on you :)  I.e. these segmented iovecs can end up overwriting
> a block.  That's ok if you're on a conventional device, but it will
> error out on a sequential write required zoned.

Fine with me then :)
Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>

--D
diff mbox series

Patch

diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c
index 2b6d4c71994d..6bcfd4c34a37 100644
--- a/fs/xfs/xfs_file.c
+++ b/fs/xfs/xfs_file.c
@@ -721,7 +721,16 @@  xfs_file_dio_write(
 	/* direct I/O must be aligned to device logical sector size */
 	if ((iocb->ki_pos | count) & target->bt_logical_sectormask)
 		return -EINVAL;
-	if ((iocb->ki_pos | count) & ip->i_mount->m_blockmask)
+
+	/*
+	 * For always COW inodes we also must check the alignment of each
+	 * individual iovec segment, as they could end up with different
+	 * I/Os due to the way bio_iov_iter_get_pages works, and we'd
+	 * then overwrite an already written block.
+	 */
+	if (((iocb->ki_pos | count) & ip->i_mount->m_blockmask) ||
+	    (xfs_is_always_cow_inode(ip) &&
+	     (iov_iter_alignment(from) & ip->i_mount->m_blockmask)))
 		return xfs_file_dio_write_unaligned(ip, iocb, from);
 	return xfs_file_dio_write_aligned(ip, iocb, from);
 }