[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH v2] migration: Support gtree migration
From: |
Auger Eric |
Subject: |
Re: [PATCH v2] migration: Support gtree migration |
Date: |
Thu, 3 Oct 2019 21:30:16 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.4.0 |
Hi Juan,
On 10/3/19 6:14 PM, Juan Quintela wrote:
> Eric Auger <address@hidden> wrote:
>> Introduce support for GTree migration. A custom save/restore
>> is implemented. Each item is made of a key and a data. For that
>> reason, 2 VMSD objects are passed into the GTree VMStateField.
>>
>> When putting the items, the tree is traversed in sorted order by
>> g_tree_foreach.
>>
>> On the get() path, gtrees must be allocated using the proper
>> key compare, key destroy and value destroy. This can be done
>> externally of automatically. If done automatically, the set of
> ^^
>
> or.
>
>> functions must be stored within the VMStateField in a new opaque
>> pointer.
>
> I am not fully convinced that the automatic mode is needed. Especially
> the ->data field. I *fear* it being abused for other cases.
OK. I implemented your suggestion, ie. using preload and it does the
job. So I don't need that field anymore.
>
>> Automatic allocation is needed for complex state save/restore.
>> For instance the virtio-iommu uses a gtree of domain and each
>> domain has a gtree of mappings.
>
> There is a pre_load() function for the VMState that creates this. it
> can be used to initualize the field value, no? That way the data part
> is not needed. I think this will make the code less complex, what do
> you think?
agreed
>
>> Special care was taken about direct key (ie. when the key is not
>> a pointer to an object but is directly a value).
>
> I am wondering if for this, it is better to add two VMSTATE (at least at
> the macro level). SIMPLE_TREE, and TREE, or whataver oyou want to call
> it. But I haven't fully looked into it.
I don't have a strong opinion here. At the moment I test the
key_vmsd->field and if it is NULL this means the key is a direct one.
Otherwise we could have 2 macros, a single info, but 2 different field
names. the name would allow to know the nature of the key.
>
> The other general "consideration" that I have is that there is neither
> of:
> - marker between elements
so we have one
> - number of elements
you don't have it
> - total size/size of elements.
you just have the size of the key and the size of the value at the
moment. I could easily add the number of nodes.
>
> That makes completelly impractical to "walk" the migration stream
> without understanding exactyl what is there. (Now, to be fair, there
> are other parts of qemu that are like that. PCI cames to mind.)
>
>> Tests are added to test save/dump of structs containing gtrees
>> including the virtio-iommu domain/mappings scenario.
>
> Really nice to have the tests. Thanks.
>
>> Signed-off-by: Eric Auger <address@hidden>
>
>
>> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
>> index 1fbfd099dd..4d9698eaab 100644
>> --- a/include/migration/vmstate.h
>> +++ b/include/migration/vmstate.h
>> @@ -171,6 +171,7 @@ struct VMStateField {
>> int version_id;
>> int struct_version_id;
>> bool (*field_exists)(void *opaque, int version_id);
>> + void *data;
>> };
>
> This is the bit that I don't really like :p
>
>>
>> +typedef struct GTreeInitData {
>> + GCompareDataFunc key_compare_func;
>> + gpointer key_compare_data;
>> + GDestroyNotify key_destroy_func;
>> + GDestroyNotify value_destroy_func;
>> +} GTreeInitData;
>
> My understanding is that if you do this on the pre_load() function, you
> don't need this at all.
yep
>
>> diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c
>> index bee658a1b2..06c4663de6 100644
>> --- a/migration/vmstate-types.c
>> +++ b/migration/vmstate-types.c
>> @@ -17,6 +17,7 @@
>> #include "qemu/error-report.h"
>> #include "qemu/queue.h"
>> #include "trace.h"
>> +#include <glib.h>
>>
>> /* bool */
>>
>> @@ -691,3 +692,135 @@ const VMStateInfo vmstate_info_qtailq = {
>> .get = get_qtailq,
>> .put = put_qtailq,
>> };
>> +
>> +struct put_gtree_data {
>> + QEMUFile *f;
>> + const VMStateField *field;
>> + QJSON *vmdesc;
>> +};
>> +
>> +static gboolean put_gtree_elem(gpointer key, gpointer value, gpointer data)
>> +{
>> + struct put_gtree_data *capsule = (struct put_gtree_data *)data;
>> + const VMStateField *field = capsule->field;
>> + QEMUFile *f = capsule->f;
>> + const VMStateDescription *key_vmsd = &field->vmsd[0];
>> + const VMStateDescription *data_vmsd = &field->vmsd[1];
>> +
>> + qemu_put_byte(f, true);
>
> Ok. there is a marker O:-)
yep
>
>> +
>> + /* put the key */
>> + if (!key_vmsd->fields) {
>> + qemu_put_be32(f, GPOINTER_TO_UINT(key));
>> + } else {
>> + if (vmstate_save_state(f, key_vmsd, key, capsule->vmdesc)) {
>> + return true;
>> + }
>> + }
>
> But it is magic to know if it is a simple or complex key.
key_vmsd->fields is used
this means you set
static const VMStateDescription vmstate_id_domain[2] = {
{}, VMSTATE_DOMAIN /* direct key, value */
};
>
>
>> + if (field->data) {
>> + init_data = (GTreeInitData *)field->data;
>> + tree = g_tree_new_full(init_data->key_compare_func,
>> + init_data->key_compare_data,
>> + init_data->key_destroy_func,
>> + init_data->value_destroy_func);
>> + *pval = tree;
>> + } else {
>> + /* tree is externally allocated */
>> + tree = *pval;
>> + }
>
> This can be simplified while we are at it.
yep, only the else block remains
>
>> + while (qemu_get_byte(f)) {
>
> If we get out of sync, for any reason, we have no way to recover. The
> only way to recover is that we don't get a "false" in this position.
adding the number of nodes should do the job
>
>
> Later, Juan.
>
So I think I will respin with the following modifications:
- use preload
- introduce 2 different macros
- encode/decode & test the number of nodes
Thank you for the quick feedbacks!
Eric