[PATCH 4/4] block: update inserted/removed nodes from BlockRAMRegistrar

Stefan Hajnoczi posted 4 patches 1 month, 2 weeks ago
Maintainers: Kevin Wolf <kwolf@redhat.com>, Hanna Reitz <hreitz@redhat.com>
There is a newer version of this series
[PATCH 4/4] block: update inserted/removed nodes from BlockRAMRegistrar
Posted by Stefan Hajnoczi 1 month, 2 weeks ago
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