From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:38984) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z3PbG-0000Wr-A6 for qemu-devel@nongnu.org; Fri, 12 Jun 2015 10:06:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Z3PbE-0002ZD-2Q for qemu-devel@nongnu.org; Fri, 12 Jun 2015 10:06:26 -0400 Received: from omzsmtpe04.verizonbusiness.com ([199.249.25.207]:49647) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Z3PbD-0002UX-Qj for qemu-devel@nongnu.org; Fri, 12 Jun 2015 10:06:24 -0400 From: Don Slutz Date: Fri, 12 Jun 2015 10:05:54 -0400 Message-Id: <1434117956-4929-8-git-send-email-dslutz@verizon.com> In-Reply-To: <1434117956-4929-1-git-send-email-dslutz@verizon.com> References: <1434117956-4929-1-git-send-email-dslutz@verizon.com> Subject: [Qemu-devel] [PATCH v7 7/9] vmport_rpc: Add migration List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: "Michael S. Tsirkin" , Markus Armbruster , Don Slutz , Luiz Capitulino , Don Slutz , Anthony Liguori , Paolo Bonzini , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Richard Henderson Signed-off-by: Don Slutz CC: Don Slutz --- hw/misc/vmport_rpc.c | 250 +++++++++++++++++++++++++++++++++++++++++++++++++++ trace-events | 2 + 2 files changed, 252 insertions(+) diff --git a/hw/misc/vmport_rpc.c b/hw/misc/vmport_rpc.c index e122bad..4984193 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; @@ -1183,6 +1191,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); @@ -1190,6 +1439,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 cfb3ffa..fbfcd86 100644 --- a/trace-events +++ b/trace-events @@ -908,6 +908,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