iomap: relax memory alignment restriction for O_DIRECT dio-mem-align
authorJens Axboe <axboe@kernel.dk>
Thu, 11 Feb 2021 15:35:43 +0000 (08:35 -0700)
committerJens Axboe <axboe@kernel.dk>
Mon, 15 Feb 2021 15:39:28 +0000 (08:39 -0700)
We currently require blocksize alignment for both position/length and the
memory range. The latter is overly restrictive, as most devices can do DMA
at a much finer granularity.

Honor the bdev setting for DMA alignment, and use that for checking if we
can process the IO or need to error it.

Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/iomap/direct-io.c

index 933f234d5becd01a7ab369abbc7476a6d0b89b14..7f962011fa0c4d2143439d9d7cb9059c6701e70f 100644 (file)
@@ -207,7 +207,8 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
 {
        unsigned int blkbits = blksize_bits(bdev_logical_block_size(iomap->bdev));
        unsigned int fs_block_size = i_blocksize(inode), pad;
-       unsigned int align = iov_iter_alignment(dio->submit.iter);
+       struct request_queue *q = bdev_get_queue(iomap->bdev);
+       unsigned long mem_align = q->dma_alignment;
        struct bio *bio;
        bool need_zeroout = false;
        bool use_fua = false;
@@ -215,7 +216,9 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
        size_t copied = 0;
        size_t orig_count;
 
-       if ((pos | length | align) & ((1 << blkbits) - 1))
+       if ((pos | length) & ((1 << blkbits) - 1))
+               return -EINVAL;
+       if (iov_iter_alignment(dio->submit.iter) & mem_align)
                return -EINVAL;
 
        if (iomap->type == IOMAP_UNWRITTEN) {
@@ -237,8 +240,7 @@ iomap_dio_bio_actor(struct inode *inode, loff_t pos, loff_t length,
                 * cache flushes on IO completion.
                 */
                if (!(iomap->flags & (IOMAP_F_SHARED|IOMAP_F_DIRTY)) &&
-                   (dio->flags & IOMAP_DIO_WRITE_FUA) &&
-                   blk_queue_fua(bdev_get_queue(iomap->bdev)))
+                   (dio->flags & IOMAP_DIO_WRITE_FUA) && blk_queue_fua(q))
                        use_fua = true;
        }