Blame SOURCES/kvm-qdev-store-DeviceState-s-canonical-path-to-use-when-.patch

9bac43
From a6dae62ef051773c0198f8ebd47a79d8f1157000 Mon Sep 17 00:00:00 2001
9bac43
From: Serhii Popovych <spopovyc@redhat.com>
9bac43
Date: Thu, 9 Nov 2017 15:30:03 +0100
9bac43
Subject: [PATCH 3/7] qdev: store DeviceState's canonical path to use when
9bac43
 unparenting
9bac43
9bac43
RH-Author: Serhii Popovych <spopovyc@redhat.com>
9bac43
Message-id: <1510241405-20597-2-git-send-email-spopovyc@redhat.com>
9bac43
Patchwork-id: 77632
9bac43
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH 1/3] qdev: store DeviceState's canonical path to use when unparenting
9bac43
Bugzilla: 1445460
9bac43
RH-Acked-by: David Gibson <dgibson@redhat.com>
9bac43
RH-Acked-by: Thomas Huth <thuth@redhat.com>
9bac43
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
9bac43
9bac43
From: Michael Roth <mdroth@linux.vnet.ibm.com>
9bac43
9bac43
device_unparent(dev, ...) is called when a device is unparented,
9bac43
either directly, or as a result of a parent device being
9bac43
finalized, and handles some final cleanup for the device. Part
9bac43
of this includes emiting a DEVICE_DELETED QMP event to notify
9bac43
management, which includes the device's path in the composition
9bac43
tree as provided by object_get_canonical_path().
9bac43
9bac43
object_get_canonical_path() assumes the device is still connected
9bac43
to the machine/root container, and will assert otherwise, but
9bac43
in some situations this isn't the case:
9bac43
9bac43
If the parent is finalized as a result of object_unparent(), it
9bac43
will still be attached to the composition tree at the time any
9bac43
children are unparented as a result of that same call to
9bac43
object_unparent(). However, in some cases, object_unparent()
9bac43
will complete without finalizing the parent device, due to
9bac43
lingering references that won't be released till some time later.
9bac43
One such example is if the parent has MemoryRegion children (which
9bac43
take a ref on their parent), who in turn have AddressSpace's (which
9bac43
take a ref on their regions), since those AddressSpaces get cleaned
9bac43
up asynchronously by the RCU thread.
9bac43
9bac43
In this case qdev:device_unparent() may be called for a child Device
9bac43
that no longer has a path to the root/machine container, causing
9bac43
object_get_canonical_path() to assert.
9bac43
9bac43
Fix this by storing the canonical path during realize() so the
9bac43
information will still be available for device_unparent() in such
9bac43
cases.
9bac43
9bac43
Cc: Michael S. Tsirkin <mst@redhat.com>
9bac43
Cc: Paolo Bonzini <pbonzini@redhat.com>
9bac43
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
9bac43
Signed-off-by: Greg Kurz <groug@kaod.org>
9bac43
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
9bac43
Tested-by: Eric Auger <eric.auger@redhat.com>
9bac43
Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
9bac43
Message-Id: <20171016222315.407-2-mdroth@linux.vnet.ibm.com>
9bac43
[Clear dev->canonical_path at the post_realize_fail label, which is
9bac43
 cleaner.  Suggested by David Gibson. - Paolo]
9bac43
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
9bac43
9bac43
(cherry picked from commit 04162f8f4bcf8c9ae2422def4357289b44208c8c)
9bac43
Signed-off-by: Serhii Popovych <spopovyc@redhat.com>
9bac43
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
9bac43
---
9bac43
 hw/core/qdev.c         | 17 ++++++++++++++---
9bac43
 include/hw/qdev-core.h |  1 +
9bac43
 2 files changed, 15 insertions(+), 3 deletions(-)
9bac43
9bac43
diff --git a/hw/core/qdev.c b/hw/core/qdev.c
9bac43
index 606ab53..0019a49 100644
9bac43
--- a/hw/core/qdev.c
9bac43
+++ b/hw/core/qdev.c
9bac43
@@ -928,6 +928,13 @@ static void device_set_realized(Object *obj, bool value, Error **errp)
9bac43
             goto post_realize_fail;
9bac43
         }
9bac43
 
9bac43
+        /*
9bac43
+         * always free/re-initialize here since the value cannot be cleaned up
9bac43
+         * in device_unrealize due to its usage later on in the unplug path
9bac43
+         */
9bac43
+        g_free(dev->canonical_path);
9bac43
+        dev->canonical_path = object_get_canonical_path(OBJECT(dev));
9bac43
+
9bac43
         if (qdev_get_vmsd(dev)) {
9bac43
             if (vmstate_register_with_alias_id(dev, -1, qdev_get_vmsd(dev), dev,
9bac43
                                                dev->instance_id_alias,
9bac43
@@ -984,6 +991,8 @@ child_realize_fail:
9bac43
     }
9bac43
 
9bac43
 post_realize_fail:
9bac43
+    g_free(dev->canonical_path);
9bac43
+    dev->canonical_path = NULL;
9bac43
     if (dc->unrealize) {
9bac43
         dc->unrealize(dev, NULL);
9bac43
     }
9bac43
@@ -1102,10 +1111,12 @@ static void device_unparent(Object *obj)
9bac43
 
9bac43
     /* Only send event if the device had been completely realized */
9bac43
     if (dev->pending_deleted_event) {
9bac43
-        gchar *path = object_get_canonical_path(OBJECT(dev));
9bac43
+        g_assert(dev->canonical_path);
9bac43
 
9bac43
-        qapi_event_send_device_deleted(!!dev->id, dev->id, path, &error_abort);
9bac43
-        g_free(path);
9bac43
+        qapi_event_send_device_deleted(!!dev->id, dev->id, dev->canonical_path,
9bac43
+                                       &error_abort);
9bac43
+        g_free(dev->canonical_path);
9bac43
+        dev->canonical_path = NULL;
9bac43
     }
9bac43
 
9bac43
     qemu_opts_del(dev->opts);
9bac43
diff --git a/include/hw/qdev-core.h b/include/hw/qdev-core.h
9bac43
index ae31728..9237b68 100644
9bac43
--- a/include/hw/qdev-core.h
9bac43
+++ b/include/hw/qdev-core.h
9bac43
@@ -153,6 +153,7 @@ struct DeviceState {
9bac43
     /*< public >*/
9bac43
 
9bac43
     const char *id;
9bac43
+    char *canonical_path;
9bac43
     bool realized;
9bac43
     bool pending_deleted_event;
9bac43
     QemuOpts *opts;
9bac43
-- 
9bac43
1.8.3.1
9bac43