Blame SOURCES/kvm-spapr-reset-DRCs-after-devices.patch

4a2fec
From 4dcd885d5308e34fb4550c20fc7ffc050e014c91 Mon Sep 17 00:00:00 2001
4a2fec
From: Laurent Vivier <lvivier@redhat.com>
4a2fec
Date: Mon, 27 Nov 2017 09:03:20 +0100
4a2fec
Subject: [PATCH 6/7] spapr: reset DRCs after devices
4a2fec
4a2fec
RH-Author: Laurent Vivier <lvivier@redhat.com>
4a2fec
Message-id: <20171127090320.32307-1-lvivier@redhat.com>
4a2fec
Patchwork-id: 77902
4a2fec
O-Subject: [RHV7.5 qemu-kvm-rhev PATCH] spapr: reset DRCs after devices
4a2fec
Bugzilla: 1516145
4a2fec
RH-Acked-by: Serhii Popovych <spopovyc@redhat.com>
4a2fec
RH-Acked-by: David Gibson <dgibson@redhat.com>
4a2fec
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
RH-Acked-by: Thomas Huth <thuth@redhat.com>
4a2fec
4a2fec
From: Greg Kurz <groug@kaod.org>
4a2fec
4a2fec
A DRC with a pending unplug request releases its associated device at
4a2fec
machine reset time.
4a2fec
4a2fec
In the case of LMB, when all DRCs for a DIMM device have been reset,
4a2fec
the DIMM gets unplugged, causing guest memory to disappear. This may
4a2fec
be very confusing for anything still using this memory.
4a2fec
4a2fec
This is exactly what happens with vhost backends, and QEMU aborts
4a2fec
with:
4a2fec
4a2fec
qemu-system-ppc64: used ring relocated for ring 2
4a2fec
qemu-system-ppc64: qemu/hw/virtio/vhost.c:649: vhost_commit: Assertion
4a2fec
 `r >= 0' failed.
4a2fec
4a2fec
The issue is that each DRC registers a QEMU reset handler, and we
4a2fec
don't control the order in which these handlers are called (ie,
4a2fec
a LMB DRC will unplug a DIMM before the virtio device using the
4a2fec
memory on this DIMM could stop its vhost backend).
4a2fec
4a2fec
To avoid such situations, let's reset DRCs after all devices
4a2fec
have been reset.
4a2fec
4a2fec
Reported-by: Mallesh N. Koti <mallesh@linux.vnet.ibm.com>
4a2fec
Signed-off-by: Greg Kurz <groug@kaod.org>
4a2fec
Reviewed-by: Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com>
4a2fec
Reviewed-by: Michael Roth <mdroth@linux.vnet.ibm.com>
4a2fec
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
4a2fec
(cherry picked from commit 82512483940c756e2db1bd67ea91b02bc29c5e01)
4a2fec
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
4a2fec
Signed-off-by: Miroslav Rezanina <mrezanin@redhat.com>
4a2fec
---
4a2fec
 hw/ppc/spapr.c     | 21 +++++++++++++++++++++
4a2fec
 hw/ppc/spapr_drc.c |  7 -------
4a2fec
 2 files changed, 21 insertions(+), 7 deletions(-)
4a2fec
4a2fec
diff --git a/hw/ppc/spapr.c b/hw/ppc/spapr.c
4a2fec
index 2065f09..6c64c55 100644
4a2fec
--- a/hw/ppc/spapr.c
4a2fec
+++ b/hw/ppc/spapr.c
4a2fec
@@ -1394,6 +1394,19 @@ static void find_unknown_sysbus_device(SysBusDevice *sbdev, void *opaque)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
+static int spapr_reset_drcs(Object *child, void *opaque)
4a2fec
+{
4a2fec
+    sPAPRDRConnector *drc =
4a2fec
+        (sPAPRDRConnector *) object_dynamic_cast(child,
4a2fec
+                                                 TYPE_SPAPR_DR_CONNECTOR);
4a2fec
+
4a2fec
+    if (drc) {
4a2fec
+        spapr_drc_reset(drc);
4a2fec
+    }
4a2fec
+
4a2fec
+    return 0;
4a2fec
+}
4a2fec
+
4a2fec
 static void ppc_spapr_reset(void)
4a2fec
 {
4a2fec
     MachineState *machine = MACHINE(qdev_get_machine());
4a2fec
@@ -1417,6 +1430,14 @@ static void ppc_spapr_reset(void)
4a2fec
     }
4a2fec
 
4a2fec
     qemu_devices_reset();
4a2fec
+
4a2fec
+    /* DRC reset may cause a device to be unplugged. This will cause troubles
4a2fec
+     * if this device is used by another device (eg, a running vhost backend
4a2fec
+     * will crash QEMU if the DIMM holding the vring goes away). To avoid such
4a2fec
+     * situations, we reset DRCs after all devices have been reset.
4a2fec
+     */
4a2fec
+    object_child_foreach_recursive(object_get_root(), spapr_reset_drcs, NULL);
4a2fec
+
4a2fec
     spapr_clear_pending_events(spapr);
4a2fec
 
4a2fec
     /*
4a2fec
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
4a2fec
index 85c999d..7d33e4c 100644
4a2fec
--- a/hw/ppc/spapr_drc.c
4a2fec
+++ b/hw/ppc/spapr_drc.c
4a2fec
@@ -455,11 +455,6 @@ void spapr_drc_reset(sPAPRDRConnector *drc)
4a2fec
     }
4a2fec
 }
4a2fec
 
4a2fec
-static void drc_reset(void *opaque)
4a2fec
-{
4a2fec
-    spapr_drc_reset(SPAPR_DR_CONNECTOR(opaque));
4a2fec
-}
4a2fec
-
4a2fec
 bool spapr_drc_needed(void *opaque)
4a2fec
 {
4a2fec
     sPAPRDRConnector *drc = (sPAPRDRConnector *)opaque;
4a2fec
@@ -517,7 +512,6 @@ static void realize(DeviceState *d, Error **errp)
4a2fec
     }
4a2fec
     vmstate_register(DEVICE(drc), spapr_drc_index(drc), &vmstate_spapr_drc,
4a2fec
                      drc);
4a2fec
-    qemu_register_reset(drc_reset, drc);
4a2fec
     trace_spapr_drc_realize_complete(spapr_drc_index(drc));
4a2fec
 }
4a2fec
 
4a2fec
@@ -528,7 +522,6 @@ static void unrealize(DeviceState *d, Error **errp)
4a2fec
     char name[256];
4a2fec
 
4a2fec
     trace_spapr_drc_unrealize(spapr_drc_index(drc));
4a2fec
-    qemu_unregister_reset(drc_reset, drc);
4a2fec
     vmstate_unregister(DEVICE(drc), &vmstate_spapr_drc, drc);
4a2fec
     root_container = container_get(object_get_root(), DRC_CONTAINER_PATH);
4a2fec
     snprintf(name, sizeof(name), "%x", spapr_drc_index(drc));
4a2fec
-- 
4a2fec
1.8.3.1
4a2fec