BlockRAMRegistrar ensures that RAMBlocks are registered with BlockDriverStates. This is essential for vdpa-blk because they need to know the memory mappings of I/O buffers. However, BlockRAMRegistrar is currently unaware of changes to the block graph and newly inserted nodes have no RAMBlocks registered.
Use the new blk_add_attach_notifier() and blk_add_detach_notifier() APIs to bring nodes up to speed when the graph changes. This fixes vdpa-blk across mirror and other operations that modify the block graph. Previously I/O would not succeed after a new node was inserted due to missing memory mappings. Buglink: https://issues.redhat.com/browse/RHEL-88175 Reported-by: Yingshun Cui <[email protected]> Signed-off-by: Stefan Hajnoczi <[email protected]> Reviewed-by: Eric Blake <[email protected]> --- include/system/block-ram-registrar.h | 2 + block/block-ram-registrar.c | 61 +++++++++++++++++++++++++++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/include/system/block-ram-registrar.h b/include/system/block-ram-registrar.h index 76c157bd54..292c197d1c 100644 --- a/include/system/block-ram-registrar.h +++ b/include/system/block-ram-registrar.h @@ -22,6 +22,8 @@ typedef struct { BlockBackend *blk; RAMBlockNotifier ram_block_notifier; + Notifier blk_attach_notifier; + Notifier blk_detach_notifier; bool ok; } BlockRAMRegistrar; diff --git a/block/block-ram-registrar.c b/block/block-ram-registrar.c index d5b84667a1..2d334c5655 100644 --- a/block/block-ram-registrar.c +++ b/block/block-ram-registrar.c @@ -7,7 +7,9 @@ #include "qemu/osdep.h" #include "system/block-backend.h" #include "system/block-ram-registrar.h" +#include "system/ramblock.h" #include "qapi/error.h" +#include "trace.h" static void ram_block_added(RAMBlockNotifier *n, void *host, size_t size, size_t max_size) @@ -22,8 +24,8 @@ static void ram_block_added(RAMBlockNotifier *n, void *host, size_t size, if (!blk_register_buf(r->blk, host, max_size, &err)) { error_report_err(err); - ram_block_notifier_remove(n); - r->ok = false; + blk_ram_registrar_destroy(r); + return; } } @@ -35,6 +37,50 @@ static void ram_block_removed(RAMBlockNotifier *n, void *host, size_t size, blk_unregister_buf(r->blk, host, max_size); } +static void blk_attached(Notifier *n, void *data) +{ + BlockRAMRegistrar *r = + container_of(n, BlockRAMRegistrar, blk_attach_notifier); + BlockBackendAttachDetachArgs *args = data; + BlockDriverState *bs = args->bs; + Error *err = NULL; + + WITH_RCU_READ_LOCK_GUARD() { + RAMBlock *rb; + + RAMBLOCK_FOREACH(rb) { + ram_addr_t max_size = qemu_ram_get_max_length(rb); + void *host = qemu_ram_get_host_addr(rb); + + if (!bdrv_register_buf(bs, host, max_size, &err)) { + goto err; + } + } + } + + return; + +err: + error_report_err(err); + blk_ram_registrar_destroy(r); +} + +static void blk_detached(Notifier *n, void *data) +{ + BlockBackendAttachDetachArgs *args = data; + BlockDriverState *bs = args->bs; + RAMBlock *rb; + + RCU_READ_LOCK_GUARD(); + + RAMBLOCK_FOREACH(rb) { + ram_addr_t max_size = qemu_ram_get_max_length(rb); + void *host = qemu_ram_get_host_addr(rb); + + bdrv_unregister_buf(bs, host, max_size); + } +} + void blk_ram_registrar_init(BlockRAMRegistrar *r, BlockBackend *blk) { r->blk = blk; @@ -47,14 +93,25 @@ void blk_ram_registrar_init(BlockRAMRegistrar *r, BlockBackend *blk) * value that does not change across resize. */ }; + r->blk_attach_notifier = (Notifier){ + .notify = blk_attached, + }; + r->blk_detach_notifier = (Notifier){ + .notify = blk_detached, + }; r->ok = true; ram_block_notifier_add(&r->ram_block_notifier); + blk_add_attach_notifier(blk, &r->blk_attach_notifier); + blk_add_detach_notifier(blk, &r->blk_detach_notifier); } void blk_ram_registrar_destroy(BlockRAMRegistrar *r) { if (r->ok) { + notifier_remove(&r->blk_detach_notifier); + notifier_remove(&r->blk_attach_notifier); ram_block_notifier_remove(&r->ram_block_notifier); + r->ok = false; } } -- 2.51.0
