Signed-off-by: Don Slutz <dsl...@verizon.com> --- hw/misc/vmport_rpc.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 8 +- 2 files changed, 255 insertions(+), 3 deletions(-)
diff --git a/hw/misc/vmport_rpc.c b/hw/misc/vmport_rpc.c index 9a32c6f..fe9cfc5 100644 --- a/hw/misc/vmport_rpc.c +++ b/hw/misc/vmport_rpc.c @@ -171,6 +171,14 @@ typedef struct VMPortRpcState { uint32_t open_cookie; channel_t chans[GUESTMSG_MAX_CHANNEL]; GHashTable *guestinfo; + /* Temporary cache for migration purposes */ + int32_t mig_chan_num; + int32_t mig_bucket_num; + uint32_t mig_guestinfo_size; + uint32_t mig_guestinfo_off; + uint8_t *mig_guestinfo_buf; + channel_control_t *mig_chans; + bucket_control_t *mig_buckets; #ifdef VMPORT_RPC_DEBUG unsigned int end; unsigned int last; @@ -1167,6 +1175,247 @@ static Property vmport_rpc_properties[] = { DEFINE_PROP_END_OF_LIST(), }; +static const VMStateDescription vmstate_vmport_rpc_chan = { + .name = "vmport_rpc/chan", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) + { + VMSTATE_UINT64(active_time, channel_control_t), + VMSTATE_UINT32(chan_id, channel_control_t), + VMSTATE_UINT32(cookie, channel_control_t), + VMSTATE_UINT32(proto_num, channel_control_t), + VMSTATE_UINT16(send_len, channel_control_t), + VMSTATE_UINT16(send_idx, channel_control_t), + VMSTATE_UINT16(send_buf_max, channel_control_t), + VMSTATE_UINT8(recv_read, channel_control_t), + VMSTATE_UINT8(recv_write, channel_control_t), + VMSTATE_END_OF_LIST() + }, +}; + +static const VMStateDescription vmstate_vmport_rpc_bucket = { + .name = "vmport_rpc/bucket", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField []) + { + VMSTATE_UINT16(recv_len, bucket_control_t), + VMSTATE_UINT16(recv_idx, bucket_control_t), + VMSTATE_UINT16(recv_buf_max, bucket_control_t), + VMSTATE_END_OF_LIST() + }, +}; + +static void vmport_rpc_size_mig_guestinfo(gpointer key, gpointer value, + gpointer opaque) +{ + VMPortRpcState *s = opaque; + unsigned int key_len = strlen(key) + 1; + guestinfo_t *gi = value; + + s->mig_guestinfo_size += 1 + key_len + 4 + gi->val_max; +} + +static void vmport_rpc_fill_mig_guestinfo(gpointer key, gpointer value, + gpointer opaque) +{ + VMPortRpcState *s = opaque; + unsigned int key_len = strlen(key) + 1; + guestinfo_t *gi = value; + + assert(gi->val_len <= gi->val_max); + trace_vmport_rpc_fill_mig_guestinfo(key_len, key_len, key, gi->val_len, + gi->val_len, gi->val_data); + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = key_len; + memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, key, key_len); + s->mig_guestinfo_off += key_len; + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_len >> 8; + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_len; + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_max >> 8; + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = gi->val_max; + memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, gi->val_data, + gi->val_max); + s->mig_guestinfo_off += gi->val_max; +} + +static int vmport_rpc_pre_load(void *opaque) +{ + VMPortRpcState *s = opaque; + + g_free(s->mig_guestinfo_buf); + s->mig_guestinfo_buf = NULL; + s->mig_guestinfo_size = 0; + s->mig_guestinfo_off = 0; + g_free(s->mig_chans); + s->mig_chans = NULL; + s->mig_chan_num = 0; + g_free(s->mig_buckets); + s->mig_buckets = NULL; + s->mig_bucket_num = 0; + + return 0; +} + +static void vmport_rpc_pre_save(void *opaque) +{ + VMPortRpcState *s = opaque; + unsigned int i; + unsigned int mig_chan_idx = 0; + unsigned int mig_bucket_idx = 0; + + (void)vmport_rpc_pre_load(opaque); + for (i = 0; i < GUESTMSG_MAX_CHANNEL; ++i) { + channel_t *c = &s->chans[i]; + + if (c->ctl.proto_num) { + unsigned int j; + + s->mig_chan_num++; + for (j = 0; j < MAX_BKTS; ++j) { + bucket_t *b = &c->recv_bkt[j]; + + s->mig_bucket_num++; + s->mig_guestinfo_size += + (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL; + } + s->mig_guestinfo_size += (c->ctl.send_buf_max + 1) * CHAR_PER_CALL; + } + } + g_hash_table_foreach(s->guestinfo, vmport_rpc_size_mig_guestinfo, s); + s->mig_guestinfo_size++; + s->mig_guestinfo_buf = g_malloc(s->mig_guestinfo_size); + s->mig_chans = g_malloc(s->mig_chan_num * sizeof(channel_control_t)); + s->mig_buckets = g_malloc(s->mig_bucket_num * sizeof(bucket_control_t)); + + for (i = 0; i < GUESTMSG_MAX_CHANNEL; ++i) { + channel_t *c = &s->chans[i]; + + if (c->ctl.proto_num) { + unsigned int j; + channel_control_t *cm = s->mig_chans + mig_chan_idx++; + unsigned int send_chars = (c->ctl.send_buf_max + 1) * CHAR_PER_CALL; + + *cm = c->ctl; + for (j = 0; j < MAX_BKTS; ++j) { + bucket_t *b = &c->recv_bkt[j]; + bucket_control_t *bm = s->mig_buckets + mig_bucket_idx++; + unsigned int recv_chars = + (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL; + + *bm = b->ctl; + memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, + b->recv.words, recv_chars); + s->mig_guestinfo_off += recv_chars; + } + memcpy(s->mig_guestinfo_buf + s->mig_guestinfo_off, + c->send.words, send_chars); + s->mig_guestinfo_off += send_chars; + } + } + g_hash_table_foreach(s->guestinfo, vmport_rpc_fill_mig_guestinfo, s); + s->mig_guestinfo_buf[s->mig_guestinfo_off++] = 0; + assert(s->mig_guestinfo_size == s->mig_guestinfo_off); + assert(s->mig_chan_num == mig_chan_idx); + assert(s->mig_bucket_num == mig_bucket_idx); +} + +static int vmport_rpc_post_load(void *opaque, int version_id) +{ + VMPortRpcState *s = opaque; + unsigned int i; + unsigned int key_len; + unsigned int mig_bucket_idx = 0; + + s->mig_guestinfo_off = 0; + for (i = 0; i < s->mig_chan_num; ++i) { + channel_control_t *cm = s->mig_chans + i; + channel_t *c = &s->chans[cm->chan_id]; + unsigned int j; + unsigned int send_chars; + + c->ctl = *cm; + for (j = 0; j < MAX_BKTS; ++j) { + bucket_t *b = &c->recv_bkt[j]; + bucket_control_t *bm = s->mig_buckets + mig_bucket_idx++; + unsigned int recv_chars; + + b->ctl = *bm; + recv_chars = (b->ctl.recv_buf_max + 1) * CHAR_PER_CALL; + b->recv.words = + g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off, + recv_chars); + s->mig_guestinfo_off += recv_chars; + } + send_chars = (c->ctl.send_buf_max + 1) * CHAR_PER_CALL; + c->send.words = g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off, + send_chars); + s->mig_guestinfo_off += send_chars; + } + assert(s->mig_bucket_num == mig_bucket_idx); + + do { + key_len = s->mig_guestinfo_buf[s->mig_guestinfo_off++]; + if (key_len) { + gpointer key = g_memdup(s->mig_guestinfo_buf + s->mig_guestinfo_off, + key_len); + guestinfo_t *gi = g_malloc(sizeof(guestinfo_t)); + unsigned int bhi, blow; + + s->mig_guestinfo_off += key_len; + bhi = s->mig_guestinfo_buf[s->mig_guestinfo_off++]; + blow = s->mig_guestinfo_buf[s->mig_guestinfo_off++]; + gi->val_len = (bhi << 8) + blow; + bhi = s->mig_guestinfo_buf[s->mig_guestinfo_off++]; + blow = s->mig_guestinfo_buf[s->mig_guestinfo_off++]; + gi->val_max = (bhi << 8) + blow; + assert(gi->val_len <= gi->val_max); + gi->val_data = g_memdup(s->mig_guestinfo_buf + + s->mig_guestinfo_off, + gi->val_max); + s->mig_guestinfo_off += gi->val_max; + trace_vmport_rpc_post_load(key_len, key_len, key, gi->val_len, + gi->val_len, gi->val_data); + assert(!g_hash_table_lookup(s->guestinfo, key)); + g_hash_table_insert(s->guestinfo, key, gi); + } + } while (key_len); + assert(s->mig_guestinfo_size == s->mig_guestinfo_off); + + (void)vmport_rpc_pre_load(opaque); + return 0; +} + +static const VMStateDescription vmstate_vmport_rpc = { + .name = "vmport_rpc", + .version_id = 1, + .minimum_version_id = 1, + .pre_save = vmport_rpc_pre_save, + .pre_load = vmport_rpc_pre_load, + .post_load = vmport_rpc_post_load, + .fields = (VMStateField[]) + { + VMSTATE_UINT64(reset_time, VMPortRpcState), + VMSTATE_UINT64(build_number_value, VMPortRpcState), + VMSTATE_UINT64(build_number_time, VMPortRpcState), + VMSTATE_UINT64(ping_time, VMPortRpcState), + VMSTATE_UINT32(open_cookie, VMPortRpcState), + VMSTATE_INT32(mig_chan_num, VMPortRpcState), + VMSTATE_STRUCT_VARRAY_ALLOC(mig_chans, VMPortRpcState, mig_chan_num, + 0, vmstate_vmport_rpc_chan, + channel_control_t), + VMSTATE_INT32(mig_bucket_num, VMPortRpcState), + VMSTATE_STRUCT_VARRAY_ALLOC(mig_buckets, VMPortRpcState, + mig_bucket_num, 0, + vmstate_vmport_rpc_bucket, + bucket_control_t), + VMSTATE_UINT32(mig_guestinfo_size, VMPortRpcState), + VMSTATE_VBUFFER_ALLOC_UINT32(mig_guestinfo_buf, VMPortRpcState, 1, + NULL, 0, mig_guestinfo_size), + VMSTATE_END_OF_LIST() + }, +}; + static void vmport_rpc_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -1174,6 +1423,7 @@ static void vmport_rpc_class_init(ObjectClass *klass, void *data) dc->realize = vmport_rpc_realize; dc->reset = vmport_rpc_reset; dc->props = vmport_rpc_properties; + dc->vmsd = &vmstate_vmport_rpc; } static const TypeInfo vmport_rpc_info = { diff --git a/trace-events b/trace-events index c1bc7e4..b55f53c 100644 --- a/trace-events +++ b/trace-events @@ -891,9 +891,9 @@ vmport_detail_rpc_end(int sub_cmd, unsigned int ax, unsigned int bx, unsigned in vmport_rpc_send_skip(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s" vmport_rpc_send_normal(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s" vmport_rpc_recv_normal(char *prefix, unsigned int end, unsigned int len, unsigned int k, size_t out_size, char *out) "%s%d[%d,%d,%zu]%s" -vmport_rpc_get_guestinfo(int klen, int kmaxlen, char *key) "klen=%d key=%.*s" -vmport_rpc_get_guestinfo_found(int vlen, int vmaxlen, char *val) "vlen=%d val=%.*s" -vmport_rpc_set_guestinfo(int klen, int kmaxlen, char *key, int vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s" +vmport_rpc_get_guestinfo(short klen, int kmaxlen, char *key) "klen=%d key=%.*s" +vmport_rpc_get_guestinfo_found(short vlen, int vmaxlen, char *val) "vlen=%d val=%.*s" +vmport_rpc_set_guestinfo(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s" vmport_rpc_set_guestinfo_bad(int i, int used_guestinfo) "i=%d not allocated, but used_guestinfo=%d" vmport_rpc_send_big(int len, size_t maxlen) "recv_len=%d >= %zd" vmport_rpc_sweep(int chan_id, long delta) "flush %d. delta=%ld" @@ -906,6 +906,8 @@ vmport_detail_rpc_process_send_size(int chan_id, int send_len) "chan %d is %d" vmport_detail_rpc_process_recv_size(int chan_id, int send_len) "chan %d is %d" vmport_rpc_process_close(int chan_id) "chan %d" vmport_rpc_process_open(int chan_id, int proto_num) "chan %d proto 0x%x" +vmport_rpc_fill_mig_guestinfo(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s" +vmport_rpc_post_load(short klen, int kmaxlen, char *key, short vlen, int vmaxlen, char *val) "klen=%d key=%.*s vlen=%d val=%.*s" # hw/scsi/vmw_pvscsi.c pvscsi_ring_init_data(uint32_t txr_len_log2, uint32_t rxr_len_log2) "TX/RX rings logarithms set to %d/%d" -- 1.8.4