Skip to content

Commit d8fbf9a

Browse files
committed
block/export: Fix graph locking in blk_get_geometry() call
blk_get_geometry() eventually calls bdrv_nb_sectors(), which is a co_wrapper_mixed_bdrv_rdlock. This means that when it is called from coroutine context, it already assume to have the graph locked. However, virtio_blk_sect_range_ok() in block/export/virtio-blk-handler.c (used by vhost-user-blk and VDUSE exports) runs in a coroutine, but doesn't take the graph lock - blk_*() functions are generally expected to do that internally. This causes an assertion failure when accessing an export for the first time if it runs in an iothread. This is an example of the crash: $ ./storage-daemon/qemu-storage-daemon --object iothread,id=th0 --blockdev file,filename=/home/kwolf/images/hd.img,node-name=disk --export vhost-user-blk,addr.type=unix,addr.path=/tmp/vhost.sock,node-name=disk,id=exp0,iothread=th0 qemu-storage-daemon: ../block/graph-lock.c:268: void assert_bdrv_graph_readable(void): Assertion `qemu_in_main_thread() || reader_count()' failed. (gdb) bt #0 0x00007ffff6eafe5c in __pthread_kill_implementation () from /lib64/libc.so.6 #1 0x00007ffff6e5fa76 in raise () from /lib64/libc.so.6 qemu#2 0x00007ffff6e497fc in abort () from /lib64/libc.so.6 qemu#3 0x00007ffff6e4971b in __assert_fail_base.cold () from /lib64/libc.so.6 qemu#4 0x00007ffff6e58656 in __assert_fail () from /lib64/libc.so.6 qemu#5 0x00005555556337a3 in assert_bdrv_graph_readable () at ../block/graph-lock.c:268 qemu#6 0x00005555555fd5a2 in bdrv_co_nb_sectors (bs=0x5555564c5ef0) at ../block.c:5847 qemu#7 0x00005555555ee949 in bdrv_nb_sectors (bs=0x5555564c5ef0) at block/block-gen.c:256 qemu#8 0x00005555555fd6b9 in bdrv_get_geometry (bs=0x5555564c5ef0, nb_sectors_ptr=0x7fffef7fedd0) at ../block.c:5884 qemu#9 0x000055555562ad6d in blk_get_geometry (blk=0x5555564cb200, nb_sectors_ptr=0x7fffef7fedd0) at ../block/block-backend.c:1624 qemu#10 0x00005555555ddb74 in virtio_blk_sect_range_ok (blk=0x5555564cb200, block_size=512, sector=0, size=512) at ../block/export/virtio-blk-handler.c:44 qemu#11 0x00005555555dd80d in virtio_blk_process_req (handler=0x5555564cbb98, in_iov=0x7fffe8003830, out_iov=0x7fffe8003860, in_num=1, out_num=0) at ../block/export/virtio-blk-handler.c:189 qemu#12 0x00005555555dd546 in vu_blk_virtio_process_req (opaque=0x7fffe8003800) at ../block/export/vhost-user-blk-server.c:66 qemu#13 0x00005555557bf4a1 in coroutine_trampoline (i0=-402635264, i1=32767) at ../util/coroutine-ucontext.c:177 qemu#14 0x00007ffff6e75c20 in ?? () from /lib64/libc.so.6 qemu#15 0x00007fffefffa870 in ?? () qemu#16 0x0000000000000000 in ?? () Fix this by creating a new blk_co_get_geometry() that takes the lock, and changing blk_get_geometry() to be a co_wrapper_mixed around it. To make the resulting code cleaner, virtio-blk-handler.c can directly call the coroutine version now (though that wouldn't be necessary for fixing the bug, taking the lock in blk_co_get_geometry() is what fixes it). Fixes: 8ab8140 Reported-by: Lukáš Doktor <[email protected]> Signed-off-by: Kevin Wolf <[email protected]> Message-Id: <[email protected]> Reviewed-by: Emanuele Giuseppe Esposito <[email protected]> Signed-off-by: Kevin Wolf <[email protected]>
1 parent e62da98 commit d8fbf9a

File tree

5 files changed

+19
-9
lines changed

5 files changed

+19
-9
lines changed

block.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5879,9 +5879,10 @@ int64_t coroutine_fn bdrv_co_getlength(BlockDriverState *bs)
58795879
}
58805880

58815881
/* return 0 as number of sectors if no device present or error */
5882-
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr)
5882+
void coroutine_fn bdrv_co_get_geometry(BlockDriverState *bs,
5883+
uint64_t *nb_sectors_ptr)
58835884
{
5884-
int64_t nb_sectors = bdrv_nb_sectors(bs);
5885+
int64_t nb_sectors = bdrv_co_nb_sectors(bs);
58855886
IO_CODE();
58865887

58875888
*nb_sectors_ptr = nb_sectors < 0 ? 0 : nb_sectors;

block/block-backend.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1615,13 +1615,16 @@ int64_t coroutine_fn blk_co_getlength(BlockBackend *blk)
16151615
return bdrv_co_getlength(blk_bs(blk));
16161616
}
16171617

1618-
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr)
1618+
void coroutine_fn blk_co_get_geometry(BlockBackend *blk,
1619+
uint64_t *nb_sectors_ptr)
16191620
{
16201621
IO_CODE();
1622+
GRAPH_RDLOCK_GUARD();
1623+
16211624
if (!blk_bs(blk)) {
16221625
*nb_sectors_ptr = 0;
16231626
} else {
1624-
bdrv_get_geometry(blk_bs(blk), nb_sectors_ptr);
1627+
bdrv_co_get_geometry(blk_bs(blk), nb_sectors_ptr);
16251628
}
16261629
}
16271630

block/export/virtio-blk-handler.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ struct virtio_blk_inhdr {
2222
unsigned char status;
2323
};
2424

25-
static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
26-
uint64_t sector, size_t size)
25+
static bool coroutine_fn
26+
virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
27+
uint64_t sector, size_t size)
2728
{
2829
uint64_t nb_sectors;
2930
uint64_t total_sectors;
@@ -41,7 +42,7 @@ static bool virtio_blk_sect_range_ok(BlockBackend *blk, uint32_t block_size,
4142
if ((sector << VIRTIO_BLK_SECTOR_BITS) % block_size) {
4243
return false;
4344
}
44-
blk_get_geometry(blk, &total_sectors);
45+
blk_co_get_geometry(blk, &total_sectors);
4546
if (sector > total_sectors || nb_sectors > total_sectors - sector) {
4647
return false;
4748
}

include/block/block-io.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ int64_t co_wrapper bdrv_get_allocated_file_size(BlockDriverState *bs);
8989

9090
BlockMeasureInfo *bdrv_measure(BlockDriver *drv, QemuOpts *opts,
9191
BlockDriverState *in_bs, Error **errp);
92-
void bdrv_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
92+
93+
void coroutine_fn GRAPH_RDLOCK
94+
bdrv_co_get_geometry(BlockDriverState *bs, uint64_t *nb_sectors_ptr);
9395

9496
int coroutine_fn GRAPH_RDLOCK
9597
bdrv_co_delete_file(BlockDriverState *bs, Error **errp);

include/sysemu/block-backend-io.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ void co_wrapper blk_eject(BlockBackend *blk, bool eject_flag);
7070
int64_t coroutine_fn blk_co_getlength(BlockBackend *blk);
7171
int64_t co_wrapper_mixed blk_getlength(BlockBackend *blk);
7272

73-
void blk_get_geometry(BlockBackend *blk, uint64_t *nb_sectors_ptr);
73+
void coroutine_fn blk_co_get_geometry(BlockBackend *blk,
74+
uint64_t *nb_sectors_ptr);
75+
void co_wrapper_mixed blk_get_geometry(BlockBackend *blk,
76+
uint64_t *nb_sectors_ptr);
7477

7578
int64_t coroutine_fn blk_co_nb_sectors(BlockBackend *blk);
7679
int64_t co_wrapper_mixed blk_nb_sectors(BlockBackend *blk);

0 commit comments

Comments
 (0)