mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
block: only use REQ_FUA for direct writes if the device supports it
When a block device does not support FUA natively, the block layer emulates it by adding a cache flush to every write bio. An O_DSYNC direct write that spans N bios then costs N flushes, rather than the single generic_write_sync() issued after the write completes. Introduce blkdev_dio_fua() to decide when REQ_FUA is set. A synchronous write can rely on generic_write_sync() when the device lacks FUA, so it sets REQ_FUA only when bdev_fua() is true. An asynchronous write completes in blkdev_bio_end_io() and cannot call the blocking generic_write_sync(), so it keeps REQ_FUA (emulated when needed) to stay durable. Suggested-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Zhenxian Ma <mzx199711@gmail.com> Signed-off-by: Zhenxian Ma <mazhenxian@xiaohongshu.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Link: https://patch.msgid.link/tencent_A41247F29AC0971AE96B52964BE4491B440A@qq.com Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
parent
bec7d36a65
commit
0d492f40c4
32
block/fops.c
32
block/fops.c
|
|
@ -26,12 +26,26 @@ static inline struct inode *bdev_file_inode(struct file *file)
|
|||
return file->f_mapping->host;
|
||||
}
|
||||
|
||||
static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
|
||||
static bool blkdev_dio_fua(struct kiocb *iocb, struct block_device *bdev)
|
||||
{
|
||||
if (!iocb_is_dsync(iocb))
|
||||
return false;
|
||||
/*
|
||||
* Async writes cannot fall back to generic_write_sync(), so they must
|
||||
* use FUA (emulated if needed); sync writes only need it when the
|
||||
* device supports FUA natively.
|
||||
*/
|
||||
if (!is_sync_kiocb(iocb))
|
||||
return true;
|
||||
return bdev_fua(bdev);
|
||||
}
|
||||
|
||||
static blk_opf_t dio_bio_write_op(struct kiocb *iocb, struct block_device *bdev)
|
||||
{
|
||||
blk_opf_t opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
|
||||
|
||||
/* avoid the need for a I/O completion work item */
|
||||
if (iocb_is_dsync(iocb))
|
||||
if (blkdev_dio_fua(iocb, bdev))
|
||||
opf |= REQ_FUA;
|
||||
return opf;
|
||||
}
|
||||
|
|
@ -75,7 +89,8 @@ static ssize_t __blkdev_direct_IO_simple(struct kiocb *iocb,
|
|||
if (user_backed_iter(iter))
|
||||
should_dirty = true;
|
||||
} else {
|
||||
bio_init(&bio, bdev, vecs, nr_pages, dio_bio_write_op(iocb));
|
||||
bio_init(&bio, bdev, vecs, nr_pages,
|
||||
dio_bio_write_op(iocb, bdev));
|
||||
}
|
||||
bio.bi_iter.bi_sector = pos >> SECTOR_SHIFT;
|
||||
bio.bi_write_hint = file_inode(iocb->ki_filp)->i_write_hint;
|
||||
|
|
@ -179,7 +194,7 @@ static ssize_t __blkdev_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
|
|||
struct blkdev_dio *dio;
|
||||
struct bio *bio;
|
||||
bool is_read = (iov_iter_rw(iter) == READ), is_sync;
|
||||
blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
|
||||
blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb, bdev);
|
||||
loff_t pos = iocb->ki_pos;
|
||||
int ret = 0;
|
||||
|
||||
|
|
@ -325,7 +340,7 @@ static ssize_t __blkdev_direct_IO_async(struct kiocb *iocb,
|
|||
unsigned int nr_pages)
|
||||
{
|
||||
bool is_read = iov_iter_rw(iter) == READ;
|
||||
blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb);
|
||||
blk_opf_t opf = is_read ? REQ_OP_READ : dio_bio_write_op(iocb, bdev);
|
||||
struct blkdev_dio *dio;
|
||||
struct bio *bio;
|
||||
loff_t pos = iocb->ki_pos;
|
||||
|
|
@ -770,6 +785,13 @@ static ssize_t blkdev_write_iter(struct kiocb *iocb, struct iov_iter *from)
|
|||
ret = direct_write_fallback(iocb, from, ret,
|
||||
blkdev_buffered_write(iocb, from));
|
||||
need_sync = true;
|
||||
} else if (ret > 0 && !blkdev_dio_fua(iocb, bdev)) {
|
||||
/*
|
||||
* The device does not support FUA, so REQ_FUA was not
|
||||
* set and the O_DSYNC direct write still needs a flush
|
||||
* to be made durable.
|
||||
*/
|
||||
need_sync = true;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user