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