[Devel] [PATCH RHEL10 COMMIT] drivers/vhost/blk: fix vhost_blk_req_done() softirq handling
Konstantin Khorenko
khorenko at virtuozzo.com
Tue Aug 25 14:03:53 MSK 2026
The commit is pushed to "branch-rh10-6.12.0-211.39.1.16.x.vz10-ovz" and will appear at git at bitbucket.org:openvz/vzkernel.git
after rh10-6.12.0-211.39.1.16.9.vz10
------>
commit e85a71f5859f94dc45079eb3b028cfcb28ea6eeb
Author: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
Date: Mon Aug 17 03:02:34 2026 +0300
drivers/vhost/blk: fix vhost_blk_req_done() softirq handling
vhost_blk_req_done() does bio_release_pages(), which may sleep on
folio_lock() when we need to dirty pages. So we get this:
[ 9120.053244] BUG: scheduling while atomic: swapper/1/0/0x00000102
...
[ 9120.079613] Hardware name: Acronis OpenStack Compute/Virtuozzo, BIOS 1.16.1-1.vz9.2 04/01/2014
[ 9120.079629] Call Trace:
[ 9120.079632] <IRQ>
[ 9120.079638] dump_stack_lvl+0x4e/0x70
[ 9120.079646] __schedule_bug.cold+0x3e/0x4a
[ 9120.079650] schedule_debug.isra.0+0x93/0xc0
[ 9120.079655] __schedule+0x7a/0x630
[ 9120.079659] ? enqueue_task_fair+0x150/0x710
[ 9120.079664] schedule+0x27/0x80
[ 9120.079666] io_schedule+0x46/0x70
[ 9120.079669] folio_wait_bit_common+0x13a/0x340
[ 9120.079686] ? __pfx_wake_page_function+0x10/0x10
[ 9120.079690] __bio_release_pages+0x25b/0x280
[ 9120.079698] vhost_blk_req_done+0x98/0xa0 [vhost_blk]
[ 9120.079702] blk_update_request+0x17c/0x420
[ 9120.079707] blk_mq_end_request+0x1c/0x30
[ 9120.079711] dm_softirq_done+0x158/0x280 [dm_mod]
[ 9120.079737] blk_complete_reqs+0x40/0x50
[ 9120.079740] handle_softirqs+0xe5/0x2a0
[ 9120.079744] __irq_exit_rcu+0xbd/0xe0
[ 9120.079746] sysvec_call_function_single+0x71/0x90
[ 9120.079750] </IRQ>
[ 9120.079751] <TASK>
[ 9120.079752] asm_sysvec_call_function_single+0x1a/0x20
Kernel already has a suitable helper: bio_check_pages_dirty(). It
takes bio ownership and dirties pages/puts bio later in some
workqueue (see bio_set_pages_dirty() annotation).
Also we should manually mark the pages dirty from
vhost_blk_bio_send(), as they can be modified through DMA.
While at here, move request posting below bio_put. I don't expect
the worker could process and reuse the request before we access
req->bb and req->bi_opf, but better be safe than sorry.
https://virtuozzo.atlassian.net/browse/VSTOR-141284
Signed-off-by: Andrey Zhadchenko <andrey.zhadchenko at virtuozzo.com>
Reviewed-by: Vasileios Almpanis <vasileios.almpanis at virtuozzo.com>
---
drivers/vhost/blk.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/drivers/vhost/blk.c b/drivers/vhost/blk.c
index c03945ac04234..dac03566bfca5 100644
--- a/drivers/vhost/blk.c
+++ b/drivers/vhost/blk.c
@@ -156,19 +156,22 @@ static void vhost_blk_req_done(struct bio *bio)
if (err)
req->bio_err = err;
- if (atomic_dec_and_test(&req->bio_nr)) {
- llist_add(&req->llnode, &req->blk_vq->llhead);
- vhost_vq_work_queue(&req->blk_vq->vq, &req->blk_vq->work);
- }
-
/*
* Bounce buffer adds kvec to bio (instead of user backed memory),
* so there is no reference/pin to bio pages in this case.
*/
- if (!req->bb)
- bio_release_pages(bio, !req->bi_opf);
+ if (!req->bb && req->bi_opf == REQ_OP_READ) {
+ bio_check_pages_dirty(bio);
+ } else {
+ if (!req->bb)
+ bio_release_pages(bio, false);
+ bio_put(bio);
+ }
- bio_put(bio);
+ if (atomic_dec_and_test(&req->bio_nr)) {
+ llist_add(&req->llnode, &req->blk_vq->llhead);
+ vhost_vq_work_queue(&req->blk_vq->vq, &req->blk_vq->work);
+ }
}
static void vhost_blk_req_cleanup(struct vhost_blk_req *req)
@@ -387,8 +390,11 @@ static inline void vhost_blk_bio_send(struct vhost_blk_req *req)
bio_nr = atomic_read(&req->bio_nr);
blk_start_plug(&plug);
- for (i = 0; i < bio_nr; i++)
+ for (i = 0; i < bio_nr; i++) {
+ if (!req->bb && req->bi_opf == REQ_OP_READ)
+ bio_set_pages_dirty(req->bio[i]);
submit_bio(req->bio[i]);
+ }
blk_finish_plug(&plug);
}
More information about the Devel
mailing list