diff mbox series

[1/2] intel_iommu: Fix root_scalable migration breakage

Message ID 20190328104933.13465-2-peterx@redhat.com
State New
Headers show
Series intel_iommu: misc scalable mode fixes for 4.0 | expand

Commit Message

Peter Xu March 28, 2019, 10:49 a.m. UTC
When introducing the initial support for scalable mode we added a
new field into vmstate however we blindly migrate that field without
notice.  That'll break migration no matter forward or backward.

The normal way should be that we use something like
VMSTATE_UINT32_TEST() or subsections for the new vmstate field however
for this case of vt-d we can even make it simpler because we've
already migrated all the registers and it'll be fairly simple that we
re-generate root_scalable field from the register values during post
load of the device.

Fixes: fb43cf739e ("intel_iommu: scalable mode emulation")
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 hw/i386/intel_iommu.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

Comments

Yi Sun March 29, 2019, 1:51 a.m. UTC | #1
On 19-03-28 18:49:32, Peter Xu wrote:
> When introducing the initial support for scalable mode we added a
> new field into vmstate however we blindly migrate that field without
> notice.  That'll break migration no matter forward or backward.
> 
Just curious, what is the scenario to break migration? From latest
qemu integrated scalable mode patches to an old qemu without scalable
mode?

The changes look good to me. Thanks for the fix!

Reviewed-by: Yi Sun <yi.y.sun@linux.intel.com>

> The normal way should be that we use something like
> VMSTATE_UINT32_TEST() or subsections for the new vmstate field however
> for this case of vt-d we can even make it simpler because we've
> already migrated all the registers and it'll be fairly simple that we
> re-generate root_scalable field from the register values during post
> load of the device.
> 
> Fixes: fb43cf739e ("intel_iommu: scalable mode emulation")
> Signed-off-by: Peter Xu <peterx@redhat.com>
Peter Xu March 29, 2019, 2:17 a.m. UTC | #2
On Fri, Mar 29, 2019 at 09:51:06AM +0800, Yi Sun wrote:
> On 19-03-28 18:49:32, Peter Xu wrote:
> > When introducing the initial support for scalable mode we added a
> > new field into vmstate however we blindly migrate that field without
> > notice.  That'll break migration no matter forward or backward.
> > 
> Just curious, what is the scenario to break migration? From latest
> qemu integrated scalable mode patches to an old qemu without scalable
> mode?

Yes, just try to fetch/build a 3.1 QEMU and migrate that to a latest
QEMU with -M pc-q35-3.1 and it'll crash with the iommu device.

> 
> The changes look good to me. Thanks for the fix!
> 
> Reviewed-by: Yi Sun <yi.y.sun@linux.intel.com>

Thanks,
diff mbox series

Patch

diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index b90de6c664..11ece40ed0 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -162,6 +162,15 @@  static inline void vtd_iommu_unlock(IntelIOMMUState *s)
     qemu_mutex_unlock(&s->iommu_lock);
 }
 
+static void vtd_update_scalable_state(IntelIOMMUState *s)
+{
+    uint64_t val = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
+
+    if (s->scalable_mode) {
+        s->root_scalable = val & VTD_RTADDR_SMT;
+    }
+}
+
 /* Whether the address space needs to notify new mappings */
 static inline gboolean vtd_as_has_map_notifier(VTDAddressSpace *as)
 {
@@ -1710,11 +1719,10 @@  static void vtd_root_table_setup(IntelIOMMUState *s)
 {
     s->root = vtd_get_quad_raw(s, DMAR_RTADDR_REG);
     s->root_extended = s->root & VTD_RTADDR_RTT;
-    if (s->scalable_mode) {
-        s->root_scalable = s->root & VTD_RTADDR_SMT;
-    }
     s->root &= VTD_RTADDR_ADDR_MASK(s->aw_bits);
 
+    vtd_update_scalable_state(s);
+
     trace_vtd_reg_dmar_root(s->root, s->root_extended);
 }
 
@@ -2945,6 +2953,15 @@  static int vtd_post_load(void *opaque, int version_id)
      */
     vtd_switch_address_space_all(iommu);
 
+    /*
+     * We don't need to migrate the root_scalable because we can
+     * simply do the calculation after the loading is complete.  We
+     * can actually do similar things with root,
+     * dmar_enabled,... however since we've have them so we need to
+     * keep them for compatibility of migration.
+     */
+    vtd_update_scalable_state(iommu);
+
     return 0;
 }
 
@@ -2966,7 +2983,6 @@  static const VMStateDescription vtd_vmstate = {
         VMSTATE_UINT8_ARRAY(csr, IntelIOMMUState, DMAR_REG_SIZE),
         VMSTATE_UINT8(iq_last_desc_type, IntelIOMMUState),
         VMSTATE_BOOL(root_extended, IntelIOMMUState),
-        VMSTATE_BOOL(root_scalable, IntelIOMMUState),
         VMSTATE_BOOL(dmar_enabled, IntelIOMMUState),
         VMSTATE_BOOL(qi_enabled, IntelIOMMUState),
         VMSTATE_BOOL(intr_enabled, IntelIOMMUState),