On 05/30/2014 06:00 PM, Alexander Graf wrote:
> 
> On 30.05.14 07:58, Alexey Kardashevskiy wrote:
>> On 05/28/2014 09:35 PM, Alexander Graf wrote:
>>> On 28.05.14 03:18, Alexey Kardashevskiy wrote:
>>>> On 05/28/2014 10:41 AM, Alexander Graf wrote:
>>>>> On 28.05.14 02:34, Alexey Kardashevskiy wrote:
>>>>>> On 05/28/2014 09:55 AM, Alexander Graf wrote:
>>> ...
>>>
>>>>>>> How do I migrate GHashTable? If I am allowed to use custom and bit more
>>>>>>> polished get/put from "[PATCH 1/2] vmstate: Add helper to enable
>>>>>>> GHashTable
>>>>>>> migration", I'll be fine.
>>>>>>> Yeah, I think it's ok to be custom in this case. Or another crazy
>>>>>>> idea -
>>>>>>> could you flatten the hash table into an array of structs that you can
>>>>>>> describe using VMState? You could then convert from the flat array
>>>>>>> to/from
>>>>>>> the GHashTable with pre_load/post_load hooks.
>>>>>> Array is exactly what I am trying to get rid of. Ok, I'll remove
>>>>>> hashmap at
>>>>>> all and implement dynamic flat array (yay, yet another bicycle!).
>>>>> Huh? The array would only live during the migration. It would be size=0
>>>>> during normal execution, but in a pre_save hook we could make size =
>>>>> hash.length() and reuse the existing, working VMState infrastructure.
>>>> When would I free that array? What if I continue the source guest and then
>>>> migrate again?
>>> Something like
>>>
>>> void pre_save(...) {
>>>      free(s->array);
>>>      s->array_len = s->hash.number_of_keys();
>>>      s->array = g_malloc(s->array_len * sizeof(struct array_elem));
>>>      for (i = 0; i < s->array_len; i++) {
>>>          s->array[i].key = s->hash.key[i];
>>>          s->array[i].value = s->hash.value[i];
>>>      }
>>> }
>>>
>>> That would waste a few bytes when we continue after migration, but it
>>> should at least keep that overhead to a minimum.
>>
>> Ok. Fine. When do I allocate an array on the destination then? Remember, I
>> do not know the number of device being transferred in advance because of
>> PCI hotplug so I cannot guess. sPAPRPHBState::pre_load is too early - I do
>> not know the size yet.
> 
> Honestly I wouldn't try to make things so complicated. You have a maximum
> size of the hash key array - there can't be more keys than devfns, right?

bus-dev-fn which gives us 65536. Which is quite a lot. If it was just
dev-fn, I would keep a static array and that's it.


> So if you just allocate the maximum size on pre_load and free it on
> post_load, you should be good.




> 
>>
>> I can:
>> 1. transfer size separately as part of sPAPRPHBState
>> 2. move this temporary array into a subsection
>> 3. allocate array in the subsection's pre_load() in a hope that QEMU will
>> call subsection's pre_load() AFTER the size of array is transferred.
>>
>> This is true for now but what if one day someone decides that all
>> pre_load() callbacks from all subsections must be called at once at the
>> beginning of the object migration? I am screwed then.
>>
>>
>>
>> Oooor I can make a patch as below (did not test it at all, just an idea).
>> Basically define VMS_ALLOC flag which will allocate necessary amount of
>> memory for that thing.
> 
> I like the patch below too though :). I'm sure that something like this
> would come in handy in other spots as well.


I go for it now, I'll post the series later tonight.


> 
> Alex
> 
>>
>>
>> I am definitely missing somewhere here, as usual, and there must be already
>> some cool hack which I do not see, so what is it?
>>
>>
>>
>> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
>> index 6af599d..7a14d26 100644
>> --- a/include/migration/vmstate.h
>> +++ b/include/migration/vmstate.h
>> @@ -101,6 +101,7 @@ enum VMStateFlags {
>>       VMS_VARRAY_UINT8     = 0x400,  /* Array with size in uint8_t field*/
>>       VMS_VARRAY_UINT32    = 0x800,  /* Array with size in uint32_t field*/
>>       VMS_MUST_EXIST       = 0x1000, /* Field must exist in input */
>> +    VMS_ALLOC            = 0x2000, /* Alloc a buffer on the destination */
>>   };
>>
>>   typedef struct {
>> @@ -750,6 +751,16 @@ static const VMStateInfo vmstate_info_hash;
>>       .offset     = vmstate_offset_value(_state, _field, qemu_hash),      \
>>   }
>>
>> +#define VMSTATE_VARRAY_STRUCT_ALLOC(_field, _state, _field_num, _version,
>> _info, _type) {\
>> +    .name       = (stringify(_field)),                               \
>> +    .version_id = (_version),                                        \
>> +    .num_offset = vmstate_offset_value(_state, _field_num, int32_t), \
>> +    .info       = &(_info),                                          \
>> +    .size       = sizeof(_type),                                     \
>> +    .flags      = VMS_VARRAY_INT32|VMS_POINTER|VMS_ALLOC,            \
>> +    .offset     = vmstate_offset_pointer(_state, _field, _type),     \
>> +}
>> +
>>   #define VMSTATE_UNUSED_V(_v, _size)                                   \
>>       VMSTATE_UNUSED_BUFFER(NULL, _v, _size)
>>
>> diff --git a/vmstate.c b/vmstate.c
>> index e1518da..7d6b0b9 100644
>> --- a/vmstate.c
>> +++ b/vmstate.c
>> @@ -48,6 +48,10 @@ static void *vmstate_base_addr(void *opaque,
>> VMStateField *field)
>>       void *base_addr = opaque + field->offset;
>>
>>       if (field->flags & VMS_POINTER) {
>> +        if (field->flags & VMS_ALLOC) {
>> +            n_elems = vmstate_n_elems(opaque, field);
>> +            *base_addr = g_malloc_n(n_elems, field->size);
>> +        }
>>           base_addr = *(void **)base_addr + field->start;
>>       }
>>
>>
>>
>>>> I mean I can solve all of this for sure but duplicating data
>>>> just to make existing migration happy is bit weird. But - I'll do what you
>>>> say here, it is no big deal :)
>>> I don't find the concept of duplicating data for migration too odd - it
>>> sounds like a good compromise between introspectability and abstraction. If
>>> you have a better suggestion I'm all open :).
>>
>>
>>
> 


-- 
Alexey

Reply via email to