Skip to content

Commit caf336f

Browse files
johnpgarryaxboe
authored andcommitted
block: Add fops atomic write support
Support atomic writes by submitting a single BIO with the REQ_ATOMIC set. It must be ensured that the atomic write adheres to its rules, like naturally aligned offset, so call blkdev_dio_invalid() -> blkdev_atomic_write_valid() [with renaming blkdev_dio_unaligned() to blkdev_dio_invalid()] for this purpose. The BIO submission path currently checks for atomic writes which are too large, so no need to check here. In blkdev_direct_IO(), if the nr_pages exceeds BIO_MAX_VECS, then we cannot produce a single BIO, so error in this case. Finally set FMODE_CAN_ATOMIC_WRITE when the bdev can support atomic writes and the associated file flag is for O_DIRECT. Reviewed-by: Martin K. Petersen <[email protected]> Signed-off-by: John Garry <[email protected]> Reviewed-by: Keith Busch <[email protected]> Acked-by: Darrick J. Wong <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 9abcfbd commit caf336f

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

block/fops.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,12 @@ static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
3434
return opf;
3535
}
3636

37-
static bool blkdev_dio_unaligned(struct block_device *bdev, loff_t pos,
38-
struct iov_iter *iter)
37+
static bool blkdev_dio_invalid(struct block_device *bdev, loff_t pos,
38+
struct iov_iter *iter, bool is_atomic)
3939
{
40+
if (is_atomic && !generic_atomic_write_valid(iter, pos))
41+
return true;
42+
4043
return pos & (bdev_logical_block_size(bdev) - 1) ||
4144
!bdev_iter_is_aligned(bdev, iter);
4245
}
@@ -72,6 +75,8 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
7275
bio.bi_iter.bi_sector = pos >> SECTOR_SHIFT;
7376
bio.bi_write_hint = file_inode(iocb->ki_filp)->i_write_hint;
7477
bio.bi_ioprio = iocb->ki_ioprio;
78+
if (iocb->ki_flags & IOCB_ATOMIC)
79+
bio.bi_opf |= REQ_ATOMIC;
7580

7681
ret = bio_iov_iter_get_pages(&bio, iter);
7782
if (unlikely(ret))
@@ -343,6 +348,9 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
343348
task_io_account_write(bio->bi_iter.bi_size);
344349
}
345350

351+
if (iocb->ki_flags & IOCB_ATOMIC)
352+
bio->bi_opf |= REQ_ATOMIC;
353+
346354
if (iocb->ki_flags & IOCB_NOWAIT)
347355
bio->bi_opf |= REQ_NOWAIT;
348356

@@ -359,12 +367,13 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
359367
static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
360368
{
361369
struct block_device *bdev = I_BDEV(iocb->ki_filp->f_mapping->host);
370+
bool is_atomic = iocb->ki_flags & IOCB_ATOMIC;
362371
unsigned int nr_pages;
363372

364373
if (!iov_iter_count(iter))
365374
return 0;
366375

367-
if (blkdev_dio_unaligned(bdev, iocb->ki_pos, iter))
376+
if (blkdev_dio_invalid(bdev, iocb->ki_pos, iter, is_atomic))
368377
return -EINVAL;
369378

370379
nr_pages = bio_iov_vecs_to_alloc(iter, BIO_MAX_VECS + 1);
@@ -373,6 +382,8 @@ static ssize_t blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
373382
return __blkdev_direct_IO_simple(iocb, iter, bdev,
374383
nr_pages);
375384
return __blkdev_direct_IO_async(iocb, iter, bdev, nr_pages);
385+
} else if (is_atomic) {
386+
return -EINVAL;
376387
}
377388
return __blkdev_direct_IO(iocb, iter, bdev, bio_max_segs(nr_pages));
378389
}
@@ -612,6 +623,9 @@ static int blkdev_open(struct inode *inode, struct file *filp)
612623
if (!bdev)
613624
return -ENXIO;
614625

626+
if (bdev_can_atomic_write(bdev) && filp->f_flags & O_DIRECT)
627+
filp->f_mode |= FMODE_CAN_ATOMIC_WRITE;
628+
615629
ret = bdev_open(bdev, mode, filp->private_data, NULL, filp);
616630
if (ret)
617631
blkdev_put_no_open(bdev);

0 commit comments

Comments
 (0)