diff mbox series

[2/2] block: fops: Do not set REQ_SYNC for async IOs

Message ID 20221126025550.967914-3-damien.lemoal@opensource.wdc.com (mailing list archive)
State New, archived
Headers show
Series Minor fixes | expand

Commit Message

Damien Le Moal Nov. 26, 2022, 2:55 a.m. UTC
Taking a blktrace of a simple fio run on a block device file using
libaio and iodepth > 1 reveals that asynchronous writes are executed as
sync writes, that is, REQ_SYNC is set for the write BIOs.

Fix this by modifying dio_bio_write_op() to set REQ_SYNC only for IOs
that are indeed synchronous ones and set REQ_IDLE only for asynchronous
IOs.

Signed-off-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
---
 block/fops.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

Comments

Christoph Hellwig Nov. 28, 2022, 3:25 p.m. UTC | #1
On Sat, Nov 26, 2022 at 11:55:50AM +0900, Damien Le Moal wrote:
> Taking a blktrace of a simple fio run on a block device file using
> libaio and iodepth > 1 reveals that asynchronous writes are executed as
> sync writes, that is, REQ_SYNC is set for the write BIOs.
> 
> Fix this by modifying dio_bio_write_op() to set REQ_SYNC only for IOs
> that are indeed synchronous ones and set REQ_IDLE only for asynchronous
> IOs.

Well, REQ_SYNC is used for I/O that some is actively waiting for,
which includs aio/io_uring I/O unlike buffered writback.

So I don't think this should be changed.
Damien Le Moal Nov. 28, 2022, 11:35 p.m. UTC | #2
On 11/29/22 00:25, Christoph Hellwig wrote:
> On Sat, Nov 26, 2022 at 11:55:50AM +0900, Damien Le Moal wrote:
>> Taking a blktrace of a simple fio run on a block device file using
>> libaio and iodepth > 1 reveals that asynchronous writes are executed as
>> sync writes, that is, REQ_SYNC is set for the write BIOs.
>>
>> Fix this by modifying dio_bio_write_op() to set REQ_SYNC only for IOs
>> that are indeed synchronous ones and set REQ_IDLE only for asynchronous
>> IOs.
> 
> Well, REQ_SYNC is used for I/O that some is actively waiting for,
> which includs aio/io_uring I/O unlike buffered writback.

OK. But then the semantic of REQ_SYNC should really be more clearly
defined. Always setting it for bdev direct write IOs regardless of the
iocb type is telling me that we should not need it at all, especially
considering that for bdev direct IO reads, it is the reverse: REQ_SYNC
is never set.

> So I don't think this should be changed.

OK. But then what ? Looking again at the block layer use of REQ_SYNC, I
do not see anything super relevant. wbt_should_throttle() use it to
detect direct writes. Some other places set that flag but it does not
seem to actually be used/tested anywhere. What am I missing ?
Damien Le Moal Nov. 28, 2022, 11:55 p.m. UTC | #3
On 11/29/22 08:35, Damien Le Moal wrote:
> On 11/29/22 00:25, Christoph Hellwig wrote:
>> On Sat, Nov 26, 2022 at 11:55:50AM +0900, Damien Le Moal wrote:
>>> Taking a blktrace of a simple fio run on a block device file using
>>> libaio and iodepth > 1 reveals that asynchronous writes are executed as
>>> sync writes, that is, REQ_SYNC is set for the write BIOs.
>>>
>>> Fix this by modifying dio_bio_write_op() to set REQ_SYNC only for IOs
>>> that are indeed synchronous ones and set REQ_IDLE only for asynchronous
>>> IOs.
>>
>> Well, REQ_SYNC is used for I/O that some is actively waiting for,
>> which includs aio/io_uring I/O unlike buffered writback.
> 
> OK. But then the semantic of REQ_SYNC should really be more clearly
> defined. Always setting it for bdev direct write IOs regardless of the
> iocb type is telling me that we should not need it at all, especially
> considering that for bdev direct IO reads, it is the reverse: REQ_SYNC
> is never set.
> 
>> So I don't think this should be changed.
> 
> OK. But then what ? Looking again at the block layer use of REQ_SYNC, I
> do not see anything super relevant. wbt_should_throttle() use it to
> detect direct writes. Some other places set that flag but it does not
> seem to actually be used/tested anywhere. What am I missing ?

I missed that most of the "magic" is happening using tests done with
op_is_sync(), which assumes that all reads are sync too. Got it.

Back to the problem at hand though, bfq uses op_is_sync() to
differentiate sync and async IOs to apply them to different queues. So
always setting REQ_SYNC for direct writes seems wrong.
diff mbox series

Patch

diff --git a/block/fops.c b/block/fops.c
index 50d245e8c913..5a4f57726828 100644
--- a/block/fops.c
+++ b/block/fops.c
@@ -34,7 +34,12 @@  static int blkdev_get_block(struct inode *inode, sector_t iblock,
 
 static blk_opf_t dio_bio_write_op(struct kiocb *iocb)
 {
-	blk_opf_t opf = REQ_OP_WRITE | REQ_SYNC | REQ_IDLE;
+	blk_opf_t opf = REQ_OP_WRITE;
+
+	if (is_sync_kiocb(iocb))
+		opf |= REQ_SYNC;
+	else
+		opf |= REQ_IDLE;
 
 	/* avoid the need for a I/O completion work item */
 	if (iocb_is_dsync(iocb))