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 <yicui@redhat.com>
Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
---
include/system/block-ram-registrar.h | 2 +
block/block-ram-registrar.c | 63 +++++++++++++++++++++++++++-
2 files changed, 63 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..a46b5a723f 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,52 @@ 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)
+{
+ BlockRAMRegistrar *r =
+ container_of(n, BlockRAMRegistrar, blk_attach_notifier);
+ 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 +95,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