Skip to content

Commit 7422bbd

Browse files
Christoph Hellwigbrauner
authored andcommitted
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: Christoph Hellwig <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: John Garry <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 7e17483 commit 7422bbd

File tree

1 file changed

+18
-3
lines changed

1 file changed

+18
-3
lines changed

fs/xfs/xfs_iops.c

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,24 @@ xfs_report_dioalign(
580580
struct xfs_buftarg *target = xfs_inode_buftarg(ip);
581581
struct block_device *bdev = target->bt_bdev;
582582

583-
stat->result_mask |= STATX_DIOALIGN;
583+
stat->result_mask |= STATX_DIOALIGN | STATX_DIO_READ_ALIGN;
584584
stat->dio_mem_align = bdev_dma_alignment(bdev) + 1;
585-
stat->dio_offset_align = bdev_logical_block_size(bdev);
585+
586+
/*
587+
* For COW inodes, we can only perform out of place writes of entire
588+
* allocation units (blocks or RT extents).
589+
* For writes smaller than the allocation unit, we must fall back to
590+
* buffered I/O to perform read-modify-write cycles. At best this is
591+
* highly inefficient; at worst it leads to page cache invalidation
592+
* races. Tell applications to avoid this by reporting the larger write
593+
* alignment in dio_offset_align, and the smaller read alignment in
594+
* dio_read_offset_align.
595+
*/
596+
stat->dio_read_offset_align = bdev_logical_block_size(bdev);
597+
if (xfs_is_cow_inode(ip))
598+
stat->dio_offset_align = xfs_inode_alloc_unitsize(ip);
599+
else
600+
stat->dio_offset_align = stat->dio_read_offset_align;
586601
}
587602

588603
static void
@@ -658,7 +673,7 @@ xfs_vn_getattr(
658673
stat->rdev = inode->i_rdev;
659674
break;
660675
case S_IFREG:
661-
if (request_mask & STATX_DIOALIGN)
676+
if (request_mask & (STATX_DIOALIGN | STATX_DIO_READ_ALIGN))
662677
xfs_report_dioalign(ip, stat);
663678
if (request_mask & STATX_WRITE_ATOMIC)
664679
xfs_report_atomic_write(ip, stat);

0 commit comments

Comments
 (0)