From: Ruslan Ruslichenko <[email protected]>

The path add possibility to bind to QEMU block backends
via the blockdev-node-name property.

This enables support for the modern -blockdev command line option.

Signed-off-by: Ruslan Ruslichenko <[email protected]>
---
 hw/core/fdt_generic_util.c | 82 ++++++++++++++++++++++++++++++++++----
 1 file changed, 75 insertions(+), 7 deletions(-)

diff --git a/hw/core/fdt_generic_util.c b/hw/core/fdt_generic_util.c
index 4ed9602d47..68dfeee096 100644
--- a/hw/core/fdt_generic_util.c
+++ b/hw/core/fdt_generic_util.c
@@ -75,6 +75,8 @@ static void fdt_get_irq_info_from_intc(FDTMachineInfo *fdti, 
qemu_irq *ret,
                                        char *intc_node_path,
                                        uint32_t *cells, uint32_t num_cells,
                                        uint32_t max, Error **errp);
+static bool fdt_attach_blockdev(FDTMachineInfo *fdti,
+                                const char *node_path, Object *dev);
 
 typedef struct QEMUIRQSharedState {
     qemu_irq sink;
@@ -241,6 +243,8 @@ FDTMachineInfo *fdt_generic_create_machine(void *fdt, 
qemu_irq *cpu_irq)
     current_machine->smp.cpus = fdt_generic_num_cpus;
     current_machine->smp.max_cpus = fdt_generic_num_cpus;
 
+    bdrv_drain_all();
+
     DB_PRINT(0, "FDT: Device tree scan complete\n");
     return fdti;
 }
@@ -987,6 +991,52 @@ static void fdt_init_qdev_array_prop(Object *obj,
     DB_PRINT_NP(0, "set property %s propname to <list>\n", propname);
 }
 
+/*
+ * Try to attach by matching drive created by '-blockdev node-name=LABEL'
+ * iff the FDT node contains property 'blockdev-node-name=LABEL'.
+ *
+ * Return false unless the given node_path has the property.
+ *
+ * Presence of the property also disables the node from ever attached
+ * to any drive created by the legacy '-drive' QEMU option.
+ *
+ * For more on '-blockdev', see:
+ *   http://events17.linuxfoundation.org/sites/events/files/slides/talk_11.pdf
+ */
+static bool fdt_attach_blockdev(FDTMachineInfo *fdti,
+                                const char *node_path, Object *dev)
+{
+    static const char propname[] = "blockdev-node-name";
+    const char *label;
+
+    /* Inspect FDT node for blockdev-only binding */
+    label = qemu_fdt_getprop(fdti->fdt, node_path, propname,
+                             NULL, NULL);
+
+    /* Skip legacy node */
+    if (!label) {
+        return false;
+    }
+
+    /*
+     * Missing matching bdev is not an error: attachment is optional.
+     *
+     * error_setg() aborts, never returns: 'goto ret' is just sanity.
+     */
+    if (!label[0]) {
+        error_setg(&error_abort, "FDT-node '%s': property '%s' = <empty>",
+                   node_path, propname);
+        return false;
+    }
+
+    if (!bdrv_find_node(label)) {
+        return false;
+    }
+
+    object_property_set_str(OBJECT(dev), "drive", label, NULL);
+    return true;
+}
+
 static void fdt_parse_node_reg_prop(FDTMachineInfo *fdti, char *node_path,
                             Object *dev)
 {
@@ -1173,6 +1223,7 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo 
*fdti, char *compat)
     char *dev_type = NULL;
     QEMUDevtreeProp *prop, *props;
     char parent_node_path[DT_PATH_LENGTH];
+    bool defer_realize = false;
 
     if (!compat) {
         return 1;
@@ -1289,6 +1340,11 @@ static int fdt_init_qdev(char *node_path, FDTMachineInfo 
*fdti, char *compat)
             continue;
         }
 
+        if (!strcmp(propname, "drive")) {
+            defer_realize = true;
+            continue;
+        }
+
         fdt_init_qdev_scalar_prop(OBJECT(dev), p, fdti, node_path, prop);
     }
 
@@ -1307,18 +1363,30 @@ static int fdt_init_qdev(char *node_path, 
FDTMachineInfo *fdti, char *compat)
              */
             fdt_init_register_user_cpu_cluster(fdti, OBJECT(dev));
         } else {
-            object_property_set_bool(OBJECT(dev), "realized", true,
-                                     &error_fatal);
-            if (dc->legacy_reset) {
-                qemu_register_reset((void (*)(void *))dc->legacy_reset,
-                                    dev);
+            if (defer_realize) {
+                FDTDeferredNode *dnode = g_new0(FDTDeferredNode, 1);
+                *dnode = (FDTDeferredNode) {
+                        .dev = DEVICE(dev),
+                        .node_path = g_strdup(node_path),
+                        .next = fdti->deferred
+                };
+                fdti->deferred = dnode;
+            } else {
+                object_property_set_bool(OBJECT(dev), "realized", true,
+                                        &error_fatal);
+                if (dc->legacy_reset) {
+                    qemu_register_reset((void (*)(void *))dc->legacy_reset,
+                                        dev);
+                }
             }
         }
     }
 
-    fdt_parse_node_reg_prop(fdti, node_path, dev);
+    if (!defer_realize) {
+        fdt_parse_node_reg_prop(fdti, node_path, dev);
 
-    fdt_parse_node_irq_prop(fdti, node_path, dev);
+        fdt_parse_node_irq_prop(fdti, node_path, dev);
+    }
 
     g_free(dev_type);
     g_free(props);
-- 
2.43.0


Reply via email to