From: Keith Busch <[email protected]>

Direct I/O request's use pages handed to the backing files unchanged, so
the backing's DMA alignment requirement applies. Track dio_mem_align and
advertise it as the device's dma_alignment so we communicate proper
limits and misaligned I/O is rejected here instead of reaching the
backend.

Signed-off-by: Keith Busch <[email protected]>
---
 drivers/block/zloop.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/block/zloop.c b/drivers/block/zloop.c
index 55eeb6aac0ea3..1149b817b5bc9 100644
--- a/drivers/block/zloop.c
+++ b/drivers/block/zloop.c
@@ -144,6 +144,7 @@ struct zloop_device {
        unsigned int            nr_conv_zones;
        unsigned int            max_open_zones;
        unsigned int            block_size;
+       unsigned int            dio_mem_align;
 
        spinlock_t              open_zones_lock;
        struct list_head        open_zones_lru_list;
@@ -1035,6 +1036,9 @@ static int zloop_get_block_size(struct zloop_device *zlo,
 {
        struct block_device *sb_bdev = 
zone->file->f_mapping->host->i_sb->s_bdev;
        struct kstat st;
+       bool have_dioalign = !vfs_getattr(&zone->file->f_path, &st,
+                                         STATX_DIOALIGN, 0) &&
+                            (st.result_mask & STATX_DIOALIGN);
 
        /*
         * If the FS block size is lower than or equal to 4K, use that as the
@@ -1044,14 +1048,25 @@ static int zloop_get_block_size(struct zloop_device 
*zlo,
         */
        if (file_inode(zone->file)->i_sb->s_blocksize <= SZ_4K)
                zlo->block_size = file_inode(zone->file)->i_sb->s_blocksize;
-       else if (!vfs_getattr(&zone->file->f_path, &st, STATX_DIOALIGN, 0) &&
-                (st.result_mask & STATX_DIOALIGN))
+       else if (have_dioalign)
                zlo->block_size = st.dio_offset_align;
        else if (sb_bdev)
                zlo->block_size = bdev_physical_block_size(sb_bdev);
        else
                zlo->block_size = SECTOR_SIZE;
 
+       /*
+        * In direct I/O the request's pages are handed to the backing files
+        * unchanged, so track their required memory alignment as a mask for
+        * dma_alignment.
+        */
+       if (have_dioalign)
+               zlo->dio_mem_align = st.dio_mem_align - 1;
+       else if (sb_bdev)
+               zlo->dio_mem_align = bdev_dma_alignment(sb_bdev);
+       else
+               zlo->dio_mem_align = SECTOR_SIZE - 1;
+
        if (zlo->zone_capacity & ((zlo->block_size >> SECTOR_SHIFT) - 1)) {
                pr_err("Zone capacity is not aligned to block size %u\n",
                       zlo->block_size);
@@ -1279,6 +1294,9 @@ static int zloop_ctl_add(struct zloop_options *opts)
 
        lim.physical_block_size = zlo->block_size;
        lim.logical_block_size = zlo->block_size;
+       /* Direct I/O hands the request's pages to the backing files unchanged. 
*/
+       if (!opts->buffered_io)
+               lim.dma_alignment = zlo->dio_mem_align;
        if (zlo->zone_append)
                lim.max_hw_zone_append_sectors = lim.max_hw_sectors;
        lim.max_open_zones = zlo->max_open_zones;
-- 
2.52.0


Reply via email to