From: "Dr. David Alan Gilbert" <dgilb...@redhat.com> Add MIG_RPCOMM_REQPAGES command on Return path for the postcopy destination to request a page from the source.
Signed-off-by: Dr. David Alan Gilbert <dgilb...@redhat.com> --- include/migration/migration.h | 3 ++ migration.c | 75 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/include/migration/migration.h b/include/migration/migration.h index 67e5528..f53add7 100644 --- a/include/migration/migration.h +++ b/include/migration/migration.h @@ -45,6 +45,7 @@ struct MigrationParams { enum mig_rpcomm_cmd { MIG_RPCOMM_INVALID = 0, /* Must be 0 */ MIG_RPCOMM_ACK, /* data (seq: be32 ) */ + MIG_RPCOMM_REQPAGES, /* data (start: be64, len: be64) */ MIG_RPCOMM_AFTERLASTVALID }; @@ -234,6 +235,8 @@ void migrate_send_rp_message(MigrationIncomingState *mis, uint16_t len, uint8_t *data); void migrate_send_rp_ack(MigrationIncomingState *mis, uint32_t value); +void migrate_send_rp_reqpages(MigrationIncomingState *mis, const char* rbname, + ram_addr_t start, ram_addr_t len); void ram_control_before_iterate(QEMUFile *f, uint64_t flags); diff --git a/migration.c b/migration.c index c7ba6a1..efad18f 100644 --- a/migration.c +++ b/migration.c @@ -105,6 +105,38 @@ void migrate_send_rp_ack(MigrationIncomingState *mis, migrate_send_rp_message(mis, MIG_RPCOMM_ACK, 4, (uint8_t *)&buf); } +/* Request a range of pages from the source VM at the given + * start address. + * rbname: Name of the RAMBlock to request the page in, if NULL it's the same + * as the last request (a name must have been given previously) + * Start: Address offset within the RB + * Len: Length in bytes required - must be a multiple of pagesize + */ +void migrate_send_rp_reqpages(MigrationIncomingState *mis, const char *rbname, + ram_addr_t start, ram_addr_t len) +{ + uint8_t bufc[16+1+255]; /* start (8 byte), len (8 byte), rbname upto 256 */ + uint64_t *buf64 = (uint64_t *)bufc; + size_t msglen = 16; /* start + len */ + + assert(!(len & 1)); + if (rbname) { + int rbname_len = strlen(rbname); + assert(rbname_len < 256); + + len |= 1; /* Flag to say we've got a name */ + bufc[msglen++] = rbname_len; + memcpy(bufc + msglen, rbname, rbname_len); + msglen += rbname_len; + } + + buf64[0] = (uint64_t)start; + buf64[0] = cpu_to_be64(buf64[0]); + buf64[1] = (uint64_t)len; + buf64[1] = cpu_to_be64(buf64[1]); + migrate_send_rp_message(mis, MIG_RPCOMM_REQPAGES, msglen, bufc); +} + void qemu_start_incoming_migration(const char *uri, Error **errp) { const char *p; @@ -776,6 +808,17 @@ static void source_return_path_bad(MigrationState *s) } /* + * Process a request for pages received on the return path, + * We're allowed to send more than requested (e.g. to round to our page size) + * and we don't need to send pages that have already been sent. + */ +static void migrate_handle_rp_reqpages(MigrationState *ms, const char* rbname, + ram_addr_t start, ram_addr_t len) +{ + DPRINTF("migrate_handle_rp_reqpages: at %zx for len %zx", start, len); +} + +/* * 'can read handler' for the fd callback * stops the data handler being called if it's gone into * error. @@ -799,9 +842,12 @@ static void source_return_path_handler(void *opaque) { MigrationState *s = opaque; QEMUFile *rp = qemu_file_get_return_path(s->file); + uint16_t expected_len; const int max_len = 512; uint8_t buf[max_len]; uint32_t tmp32; + uint64_t tmp64a, tmp64b; + char *tmpstr; int res; DPRINTF("RP: Receive\n"); @@ -811,7 +857,6 @@ static void source_return_path_handler(void *opaque) } if (s->rp_state.header_com == MIG_RPCOMM_INVALID) { - uint16_t expected_len; /* No command stored, so we're expecting a new header */ res = qemu_peek_buffer(rp, buf, 4, 0); @@ -832,6 +877,11 @@ static void source_return_path_handler(void *opaque) expected_len = 4; break; + case MIG_RPCOMM_REQPAGES: + /* 16 byte start/len _possibly_ plus an id str */ + expected_len = 16 + 256; + break; + default: DPRINTF("RP: Received invalid cmd 0x%04x length 0x%04x\n", s->rp_state.header_com, s->rp_state.header_len); @@ -866,6 +916,29 @@ static void source_return_path_handler(void *opaque) atomic_xchg(&s->rp_state.latest_ack, tmp32); break; + case MIG_RPCOMM_REQPAGES: + tmp64a = be64_to_cpup((uint64_t *)buf); /* Start */ + tmp64b = be64_to_cpup(((uint64_t *)buf)+1); /* Len */ + tmpstr = NULL; + if (tmp64b & 1) { + /* Now we expect an idstr */ + tmp32 = buf[16]; /* Length of the following idstr */ + tmpstr = (char *)&buf[17]; + buf[17+tmp32] = '\0'; + expected_len = 16+1+tmp32; + } else { + expected_len = 16; + } + if (s->rp_state.header_len != expected_len) { + error_report("RP: Received ReqPage with length %d expecting %d", + s->rp_state.header_len, expected_len); + source_return_path_bad(s); + } + migrate_handle_rp_reqpages(s, tmpstr, + (ram_addr_t)tmp64a, + (ram_addr_t)tmp64b); + break; + default: /* This shouldn't happen because we should catch this above */ DPRINTF("RP: Bad header_com in dispatch\n"); -- 1.9.3