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

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