* Eric Auger (eric.au...@redhat.com) wrote: > Add Migration support. We rely on recently added gtree and qlist > migration. Besides, we have to fixup end point <-> domain link. > > Indeed each domain has a list of endpoints attached to it. And each > endpoint has a pointer to its domain. > > Raw gtree and qlist migration cannot handle this as it re-allocates > all the nodes while reconstructing the trees/lists. > > So in post_load we re-construct the relationship between endpoints > and domains. > > Signed-off-by: Eric Auger <eric.au...@redhat.com>
>From the migration side of things, Acked-by: Dr. David Alan Gilbert <dgilb...@redhat.com> > --- > hw/virtio/virtio-iommu.c | 127 ++++++++++++++++++++++++++++++++++++--- > 1 file changed, 117 insertions(+), 10 deletions(-) > > diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c > index c5b202fab7..4e92fc0c95 100644 > --- a/hw/virtio/virtio-iommu.c > +++ b/hw/virtio/virtio-iommu.c > @@ -692,16 +692,6 @@ static void virtio_iommu_set_features(VirtIODevice > *vdev, uint64_t val) > trace_virtio_iommu_set_features(dev->acked_features); > } > > -/* > - * Migration is not yet supported: most of the state consists > - * of balanced binary trees which are not yet ready for getting > - * migrated > - */ > -static const VMStateDescription vmstate_virtio_iommu_device = { > - .name = "virtio-iommu-device", > - .unmigratable = 1, > -}; > - > static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data) > { > uint ua = GPOINTER_TO_UINT(a); > @@ -778,6 +768,123 @@ static void virtio_iommu_instance_init(Object *obj) > { > } > > +#define VMSTATE_INTERVAL \ > +{ \ > + .name = "interval", \ > + .version_id = 1, \ > + .minimum_version_id = 1, \ > + .fields = (VMStateField[]) { \ > + VMSTATE_UINT64(low, viommu_interval), \ > + VMSTATE_UINT64(high, viommu_interval), \ > + VMSTATE_END_OF_LIST() \ > + } \ > +} > + > +#define VMSTATE_MAPPING \ > +{ \ > + .name = "mapping", \ > + .version_id = 1, \ > + .minimum_version_id = 1, \ > + .fields = (VMStateField[]) { \ > + VMSTATE_UINT64(phys_addr, viommu_mapping), \ > + VMSTATE_UINT32(flags, viommu_mapping), \ > + VMSTATE_END_OF_LIST() \ > + }, \ > +} > + > +static const VMStateDescription vmstate_interval_mapping[2] = { > + VMSTATE_MAPPING, /* value */ > + VMSTATE_INTERVAL /* key */ > +}; > + > +static int domain_preload(void *opaque) > +{ > + viommu_domain *domain = opaque; > + > + domain->mappings = g_tree_new_full((GCompareDataFunc)interval_cmp, > + NULL, g_free, g_free); > + return 0; > +} > + > +static const VMStateDescription vmstate_endpoint = { > + .name = "endpoint", > + .version_id = 1, > + .minimum_version_id = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(id, viommu_endpoint), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static const VMStateDescription vmstate_domain = { > + .name = "domain", > + .version_id = 1, > + .minimum_version_id = 1, > + .pre_load = domain_preload, > + .fields = (VMStateField[]) { > + VMSTATE_UINT32(id, viommu_domain), > + VMSTATE_GTREE_V(mappings, viommu_domain, 1, > + vmstate_interval_mapping, > + viommu_interval, viommu_mapping), > + VMSTATE_QLIST_V(endpoint_list, viommu_domain, 1, > + vmstate_endpoint, viommu_endpoint, next), > + VMSTATE_END_OF_LIST() > + } > +}; > + > +static gboolean reconstruct_ep_domain_link(gpointer key, gpointer value, > + gpointer data) > +{ > + viommu_domain *d = (viommu_domain *)value; > + viommu_endpoint *iter, *tmp; > + viommu_endpoint *ep = (viommu_endpoint *)data; > + > + QLIST_FOREACH_SAFE(iter, &d->endpoint_list, next, tmp) { > + if (iter->id == ep->id) { > + /* remove the ep */ > + QLIST_REMOVE(iter, next); > + g_free(iter); > + /* replace it with the good one */ > + QLIST_INSERT_HEAD(&d->endpoint_list, ep, next); > + /* update the domain */ > + ep->domain = d; > + return true; /* stop the search */ > + } > + } > + return false; /* continue the traversal */ > +} > + > +static gboolean fix_endpoint(gpointer key, gpointer value, gpointer data) > +{ > + VirtIOIOMMU *s = (VirtIOIOMMU *)data; > + > + g_tree_foreach(s->domains, reconstruct_ep_domain_link, value); > + return false; > +} > + > +static int iommu_post_load(void *opaque, int version_id) > +{ > + VirtIOIOMMU *s = opaque; > + > + g_tree_foreach(s->endpoints, fix_endpoint, s); > + return 0; > +} > + > +static const VMStateDescription vmstate_virtio_iommu_device = { > + .name = "virtio-iommu-device", > + .minimum_version_id = 1, > + .version_id = 1, > + .post_load = iommu_post_load, > + .fields = (VMStateField[]) { > + VMSTATE_GTREE_DIRECT_KEY_V(domains, VirtIOIOMMU, 1, > + &vmstate_domain, viommu_domain), > + VMSTATE_GTREE_DIRECT_KEY_V(endpoints, VirtIOIOMMU, 1, > + &vmstate_endpoint, viommu_endpoint), > + VMSTATE_END_OF_LIST() > + }, > +}; > + > + > static const VMStateDescription vmstate_virtio_iommu = { > .name = "virtio-iommu", > .minimum_version_id = 1, > -- > 2.20.1 > -- Dr. David Alan Gilbert / dgilb...@redhat.com / Manchester, UK