yeahuh / rpms / qemu-kvm

Forked from rpms/qemu-kvm 2 years ago
Clone
8fced6
From 9ebed8090b88282f9b7432258df9182b9d3944ee Mon Sep 17 00:00:00 2001
8fced6
From: Greg Kurz <gkurz@redhat.com>
8fced6
Date: Tue, 19 Jan 2021 15:09:52 -0500
8fced6
Subject: [PATCH 4/9] spapr: Fix handling of unplugged devices during CAS and
8fced6
 migration
8fced6
8fced6
RH-Author: Greg Kurz <gkurz@redhat.com>
8fced6
Message-id: <20210119150954.1017058-5-gkurz@redhat.com>
8fced6
Patchwork-id: 100685
8fced6
O-Subject: [RHEL-8.4.0 qemu-kvm PATCH v2 4/6] spapr: Fix handling of unplugged devices during CAS and migration
8fced6
Bugzilla: 1901837
8fced6
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
8fced6
RH-Acked-by: Laurent Vivier <lvivier@redhat.com>
8fced6
RH-Acked-by: David Gibson <dgibson@redhat.com>
8fced6
8fced6
From: Greg Kurz <groug@kaod.org>
8fced6
8fced6
We already detect if a device is being hot plugged before CAS to trigger
8fced6
a CAS reboot and during migration to migrate the state of the associated
8fced6
DRC. But hot unplugging a device is also an asynchronous operation that
8fced6
requires the guest to take action. This means that if the guest is migrated
8fced6
after the hot unplug event was sent but before it could release the device
8fced6
with RTAS, the destination QEMU doesn't know about the pending unplug
8fced6
operation and doesn't actually remove the device when the guest finally
8fced6
releases it.
8fced6
8fced6
Similarly, if the unplug request is fired before CAS, the guest isn't
8fced6
notified of the change, just like with hotplug. It ends up booting with
8fced6
the device still present in the DT and configures it, just like it was
8fced6
never removed. Even weirder, since the event is still queued, it will
8fced6
be eventually processed when some other unrelated event is posted to
8fced6
the guest.
8fced6
8fced6
Enhance spapr_drc_transient() to also return true if an unplug request is
8fced6
pending. This fixes the issue at CAS with a CAS reboot request and
8fced6
causes the DRC state to be migrated. Some extra care is still needed to
8fced6
inform the destination that an unplug request is pending : migrate the
8fced6
unplug_requested field of the DRC in an optional subsection. This might
8fced6
break backwards migration, but this is still better than ending with
8fced6
an inconsistent guest.
8fced6
8fced6
Signed-off-by: Greg Kurz <groug@kaod.org>
8fced6
Message-Id: <158169248798.3465937.1108351365840514270.stgit@bahia.lan>
8fced6
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
8fced6
(cherry picked from commit ab8584349c476f9818dc6403359c85f9ab0ad5eb)
8fced6
Signed-off-by: Greg Kurz <gkurz@redhat.com>
8fced6
Signed-off-by: Jon Maloy <jmaloy.redhat.com>
8fced6
---
8fced6
 hw/ppc/spapr_drc.c | 25 +++++++++++++++++++++++--
8fced6
 1 file changed, 23 insertions(+), 2 deletions(-)
8fced6
8fced6
diff --git a/hw/ppc/spapr_drc.c b/hw/ppc/spapr_drc.c
8fced6
index 9b498d429e..897bb7aae0 100644
8fced6
--- a/hw/ppc/spapr_drc.c
8fced6
+++ b/hw/ppc/spapr_drc.c
8fced6
@@ -455,6 +455,22 @@ void spapr_drc_reset(SpaprDrc *drc)
8fced6
     }
8fced6
 }
8fced6
 
8fced6
+static bool spapr_drc_unplug_requested_needed(void *opaque)
8fced6
+{
8fced6
+    return spapr_drc_unplug_requested(opaque);
8fced6
+}
8fced6
+
8fced6
+static const VMStateDescription vmstate_spapr_drc_unplug_requested = {
8fced6
+    .name = "spapr_drc/unplug_requested",
8fced6
+    .version_id = 1,
8fced6
+    .minimum_version_id = 1,
8fced6
+    .needed = spapr_drc_unplug_requested_needed,
8fced6
+    .fields  = (VMStateField []) {
8fced6
+        VMSTATE_BOOL(unplug_requested, SpaprDrc),
8fced6
+        VMSTATE_END_OF_LIST()
8fced6
+    }
8fced6
+};
8fced6
+
8fced6
 bool spapr_drc_transient(SpaprDrc *drc)
8fced6
 {
8fced6
     SpaprDrcClass *drck = SPAPR_DR_CONNECTOR_GET_CLASS(drc);
8fced6
@@ -470,9 +486,10 @@ bool spapr_drc_transient(SpaprDrc *drc)
8fced6
     /*
8fced6
      * We need to reset the DRC at CAS or to migrate the DRC state if it's
8fced6
      * not equal to the expected long-term state, which is the same as the
8fced6
-     * coldplugged initial state.
8fced6
+     * coldplugged initial state, or if an unplug request is pending.
8fced6
      */
8fced6
-    return (drc->state != drck->ready_state);
8fced6
+    return drc->state != drck->ready_state ||
8fced6
+        spapr_drc_unplug_requested(drc);
8fced6
 }
8fced6
 
8fced6
 static bool spapr_drc_needed(void *opaque)
8fced6
@@ -488,6 +505,10 @@ static const VMStateDescription vmstate_spapr_drc = {
8fced6
     .fields  = (VMStateField []) {
8fced6
         VMSTATE_UINT32(state, SpaprDrc),
8fced6
         VMSTATE_END_OF_LIST()
8fced6
+    },
8fced6
+    .subsections = (const VMStateDescription * []) {
8fced6
+        &vmstate_spapr_drc_unplug_requested,
8fced6
+        NULL
8fced6
     }
8fced6
 };
8fced6
 
8fced6
-- 
8fced6
2.18.2
8fced6