Unverified Commit 7422bbd0 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Christian Brauner
Browse files

xfs: report the correct read/write dio alignment for reflinked inodes



For I/O to reflinked blocks we always need to write an entire new
file system block, and the code enforces the file system block alignment
for the entire file if it has any reflinked blocks.

Use the new STATX_DIO_READ_ALIGN flag to report the asymmetric read
vs write alignments for reflinked files.

Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250109083109.1441561-5-hch@lst.de


Reviewed-by: default avatarJohn Garry <john.g.garry@oracle.com>
Reviewed-by: default avatarDarrick J. Wong <djwong@kernel.org>
Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parent 7e17483c
Loading
Loading
Loading
Loading
+18 −3
Original line number Diff line number Diff line
@@ -580,9 +580,24 @@ xfs_report_dioalign(
	struct xfs_buftarg	*target = xfs_inode_buftarg(ip);
	struct block_device	*bdev = target->bt_bdev;

	stat->result_mask |= STATX_DIOALIGN;
	stat->result_mask |= STATX_DIOALIGN | STATX_DIO_READ_ALIGN;
	stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
	stat->dio_offset_align = bdev_logical_block_size(bdev);

	/*
	 * For COW inodes, we can only perform out of place writes of entire
	 * allocation units (blocks or RT extents).
	 * For writes smaller than the allocation unit, we must fall back to
	 * buffered I/O to perform read-modify-write cycles.  At best this is
	 * highly inefficient; at worst it leads to page cache invalidation
	 * races.  Tell applications to avoid this by reporting the larger write
	 * alignment in dio_offset_align, and the smaller read alignment in
	 * dio_read_offset_align.
	 */
	stat->dio_read_offset_align = bdev_logical_block_size(bdev);
	if (xfs_is_cow_inode(ip))
		stat->dio_offset_align = xfs_inode_alloc_unitsize(ip);
	else
		stat->dio_offset_align = stat->dio_read_offset_align;
}

static void
@@ -658,7 +673,7 @@ xfs_vn_getattr(
		stat->rdev = inode->i_rdev;
		break;
	case S_IFREG:
		if (request_mask & STATX_DIOALIGN)
		if (request_mask & (STATX_DIOALIGN | STATX_DIO_READ_ALIGN))
			xfs_report_dioalign(ip, stat);
		if (request_mask & STATX_WRITE_ATOMIC)
			xfs_report_atomic_write(ip, stat);