Refer to commit 9a85e4b8f672016adbf7b7d5beaab2a99b9b5615 to support for GHashTable migration. A custom save/restore is implemented. Each item is made of a key and a data. Currently, only pointer-type keys and values are supported. On the get() path, ghashtable must be allocated using the proper key compare, key destroy and value destroy. This must be handled beforehand, for example in a pre_load method.
Signed-off-by: hongmianquan <[email protected]> --- include/migration/vmstate.h | 22 ++++++ migration/trace-events | 5 ++ migration/vmstate-types.c | 147 ++++++++++++++++++++++++++++++++++++ 3 files changed, 174 insertions(+) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 89f9f49d20..cd7893c66a 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -265,6 +265,7 @@ extern const VMStateInfo vmstate_info_bitmap; extern const VMStateInfo vmstate_info_qtailq; extern const VMStateInfo vmstate_info_gtree; extern const VMStateInfo vmstate_info_qlist; +extern const VMStateInfo vmstate_info_ghash; #define type_check_2darray(t1,t2,n,m) ((t1(*)[n][m])0 - (t2*)0) /* @@ -882,6 +883,27 @@ extern const VMStateInfo vmstate_info_qlist; .start = offsetof(_type, _next), \ } +/* + * For migrating a GHashTable whose key is a pointer to _key_type and the + * value, a pointer to _val_type + * The target hashtable must have been properly initialized + * _vmsd: Start address of the 2 element array containing the data vmsd + * and the key vmsd, in that order + * _key_type: type of the key + * _val_type: type of the value + */ +#define VMSTATE_GHASH_V(_field, _state, _version, _vmsd, \ + _key_type, _val_type) \ +{ \ + .name = (stringify(_field)), \ + .version_id = (_version), \ + .vmsd = (_vmsd), \ + .info = &vmstate_info_ghash, \ + .start = sizeof(_key_type), \ + .size = sizeof(_val_type), \ + .offset = offsetof(_state, _field), \ +} + /* _f : field name _f_n : num of elements field_name _n : num of elements diff --git a/migration/trace-events b/migration/trace-events index 90629f828f..f00f4c3e74 100644 --- a/migration/trace-events +++ b/migration/trace-events @@ -86,6 +86,11 @@ get_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)" put_qlist(const char *field_name, const char *vmsd_name, int version_id) "%s(%s v%d)" put_qlist_end(const char *field_name, const char *vmsd_name) "%s(%s)" +get_ghash(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d" +get_ghash_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, int ret) "%s(%s/%s) %d" +put_ghash(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, uint32_t nnodes) "%s(%s/%s) nnodes=%d" +put_ghash_end(const char *field_name, const char *key_vmsd_name, const char *val_vmsd_name, int ret) "%s(%s/%s) %d" + # qemu-file.c qemu_file_fclose(void) "" qemu_file_put_fd(const char *name, int fd, int ret) "ioc %s, fd %d -> status %d" diff --git a/migration/vmstate-types.c b/migration/vmstate-types.c index 89cb211472..e6c3573789 100644 --- a/migration/vmstate-types.c +++ b/migration/vmstate-types.c @@ -942,3 +942,150 @@ const VMStateInfo vmstate_info_qlist = { .get = get_qlist, .put = put_qlist, }; + +struct put_ghash_data { + QEMUFile *f; + const VMStateDescription *key_vmsd; + const VMStateDescription *val_vmsd; + JSONWriter *vmdesc; + int ret; +}; + +static gboolean put_ghash_elem(gpointer key, gpointer value, gpointer data) +{ + struct put_ghash_data *capsule = (struct put_ghash_data *)data; + QEMUFile *f = capsule->f; + int ret; + Error *local_err = NULL; + + qemu_put_byte(f, true); + + /* put the key */ + ret = vmstate_save_state(f, capsule->key_vmsd, key, + capsule->vmdesc, &local_err); + if (ret) { + error_report_err(local_err); + capsule->ret = ret; + return false; + } + + /* put the data */ + ret = vmstate_save_state(f, capsule->val_vmsd, value, + capsule->vmdesc, &local_err); + if (ret) { + error_report_err(local_err); + capsule->ret = ret; + return false; + } + return true; +} + +static int put_ghash(QEMUFile *f, void *pv, size_t unused_size, + const VMStateField *field, JSONWriter *vmdesc) +{ + const VMStateDescription *key_vmsd = &field->vmsd[1]; + const VMStateDescription *val_vmsd = &field->vmsd[0]; + struct put_ghash_data capsule = { + .f = f, + .key_vmsd = key_vmsd, + .val_vmsd = val_vmsd, + .vmdesc = vmdesc, + .ret = 0}; + GHashTable **pval = pv; + GHashTable *hash = *pval; + GHashTableIter iter; + gpointer key, value; + uint32_t nnodes = g_hash_table_size(hash); + int ret; + + trace_put_ghash(field->name, key_vmsd->name, val_vmsd->name, nnodes); + qemu_put_be32(f, nnodes); + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, &key, &value)) { + if (!put_ghash_elem(key, value, (gpointer)&capsule)) { + break; + } + } + qemu_put_byte(f, false); + ret = capsule.ret; + if (ret) { + error_report("%s : failed to save ghash (%d)", field->name, ret); + } + trace_put_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +} + +static int get_ghash(QEMUFile *f, void *pv, size_t unused_size, + const VMStateField *field) +{ + const VMStateDescription *key_vmsd = &field->vmsd[1]; + const VMStateDescription *val_vmsd = &field->vmsd[0]; + int version_id = field->version_id; + size_t key_size = field->start; + size_t val_size = field->size; + int nnodes, count = 0; + GHashTable **pval = pv; + GHashTable *hash = *pval; + void *key, *val; + int ret = 0; + Error *local_err = NULL; + + if (version_id > key_vmsd->version_id) { + error_report("%s %s", key_vmsd->name, "too new"); + return -EINVAL; + } + if (version_id < key_vmsd->minimum_version_id) { + error_report("%s %s", key_vmsd->name, "too old"); + return -EINVAL; + } + if (version_id > val_vmsd->version_id) { + error_report("%s %s", val_vmsd->name, "too new"); + return -EINVAL; + } + if (version_id < val_vmsd->minimum_version_id) { + error_report("%s %s", val_vmsd->name, "too old"); + return -EINVAL; + } + + nnodes = qemu_get_be32(f); + trace_get_ghash(field->name, key_vmsd->name, val_vmsd->name, nnodes); + + while (qemu_get_byte(f)) { + if ((++count) > nnodes) { + ret = -EINVAL; + break; + } + key = g_malloc0(key_size); + ret = vmstate_load_state(f, key_vmsd, key, version_id, &local_err); + if (ret) { + error_report_err(local_err); + goto key_error; + } + val = g_malloc0(val_size); + ret = vmstate_load_state(f, val_vmsd, val, version_id, &local_err); + if (ret) { + error_report_err(local_err); + goto val_error; + } + g_hash_table_insert(hash, key, val); + } + if (count != nnodes) { + error_report("%s inconsistent stream when loading the ghash", + field->name); + return -EINVAL; + } + trace_get_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +val_error: + g_free(val); +key_error: + g_free(key); + trace_get_ghash_end(field->name, key_vmsd->name, val_vmsd->name, ret); + return ret; +} + +const VMStateInfo vmstate_info_ghash = { + .name = "ghash", + .get = get_ghash, + .put = put_ghash, +}; -- 2.32.1 (Apple Git-133)
