From eb5c936e81e2e292ceefec9b6628862599f71c17 Mon Sep 17 00:00:00 2001 From: Soren Brinkmann Date: Thu, 13 Aug 2015 23:16:27 -0700 Subject: [PATCH 1/9] vmstate: Remove redefinition of VMSTATE_UINT32_ARRAY The macro is defined twice in identical ways. Signed-off-by: Soren Brinkmann Message-Id: <1439532987-16335-1-git-send-email-soren.brinkmann@xilinx.com> Reviewed-by: Peter Maydell Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- include/migration/vmstate.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h index 2e5a97dec4..9a65522da1 100644 --- a/include/migration/vmstate.h +++ b/include/migration/vmstate.h @@ -754,9 +754,6 @@ extern const VMStateInfo vmstate_info_bitmap; #define VMSTATE_UINT32_SUB_ARRAY(_f, _s, _start, _num) \ VMSTATE_SUB_ARRAY(_f, _s, _start, _num, 0, vmstate_info_uint32, uint32_t) -#define VMSTATE_UINT32_ARRAY(_f, _s, _n) \ - VMSTATE_UINT32_ARRAY_V(_f, _s, _n, 0) - #define VMSTATE_INT64_ARRAY_V(_f, _s, _n, _v) \ VMSTATE_ARRAY(_f, _s, _n, _v, vmstate_info_int64, int64_t) From 2f68e39956b7504f6669671fd95b70859afc340d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Aug 2015 11:51:30 +0100 Subject: [PATCH 2/9] migration/ram.c: Use RAMBlock rather than MemoryRegion RAM migration mainly works on RAMBlocks but in a few places uses data from MemoryRegions to access the same information that's already held in RAMBlocks; clean it up just to avoid the MemoryRegion use. Signed-off-by: Dr. David Alan Gilbert Message-Id: <1439463094-5394-2-git-send-email-dgilbert@redhat.com> Acked-by: Paolo Bonzini Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- migration/ram.c | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 7f007e6432..7df9157ec7 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -497,13 +497,13 @@ static int save_xbzrle_page(QEMUFile *f, uint8_t **current_data, /* Called with rcu_read_lock() to protect migration_bitmap */ static inline -ram_addr_t migration_bitmap_find_and_reset_dirty(MemoryRegion *mr, +ram_addr_t migration_bitmap_find_and_reset_dirty(RAMBlock *rb, ram_addr_t start) { - unsigned long base = mr->ram_addr >> TARGET_PAGE_BITS; + unsigned long base = rb->offset >> TARGET_PAGE_BITS; unsigned long nr = base + (start >> TARGET_PAGE_BITS); - uint64_t mr_size = TARGET_PAGE_ALIGN(memory_region_size(mr)); - unsigned long size = base + (mr_size >> TARGET_PAGE_BITS); + uint64_t rb_size = rb->used_length; + unsigned long size = base + (rb_size >> TARGET_PAGE_BITS); unsigned long *bitmap; unsigned long next; @@ -573,7 +573,7 @@ static void migration_bitmap_sync(void) qemu_mutex_lock(&migration_bitmap_mutex); rcu_read_lock(); QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { - migration_bitmap_sync_range(block->mr->ram_addr, block->used_length); + migration_bitmap_sync_range(block->offset, block->used_length); } rcu_read_unlock(); qemu_mutex_unlock(&migration_bitmap_mutex); @@ -668,12 +668,11 @@ static int ram_save_page(QEMUFile *f, RAMBlock* block, ram_addr_t offset, int pages = -1; uint64_t bytes_xmit; ram_addr_t current_addr; - MemoryRegion *mr = block->mr; uint8_t *p; int ret; bool send_async = true; - p = memory_region_get_ram_ptr(mr) + offset; + p = block->host + offset; /* In doubt sent page as normal */ bytes_xmit = 0; @@ -744,7 +743,7 @@ static int do_compress_ram_page(CompressParam *param) RAMBlock *block = param->block; ram_addr_t offset = param->offset; - p = memory_region_get_ram_ptr(block->mr) + (offset & TARGET_PAGE_MASK); + p = block->host + (offset & TARGET_PAGE_MASK); bytes_sent = save_page_header(param->file, block, offset | RAM_SAVE_FLAG_COMPRESS_PAGE); @@ -852,11 +851,10 @@ static int ram_save_compressed_page(QEMUFile *f, RAMBlock *block, { int pages = -1; uint64_t bytes_xmit; - MemoryRegion *mr = block->mr; uint8_t *p; int ret; - p = memory_region_get_ram_ptr(mr) + offset; + p = block->host + offset; bytes_xmit = 0; ret = ram_control_save_page(f, block->offset, @@ -929,14 +927,12 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, ram_addr_t offset = last_offset; bool complete_round = false; int pages = 0; - MemoryRegion *mr; if (!block) block = QLIST_FIRST_RCU(&ram_list.blocks); while (true) { - mr = block->mr; - offset = migration_bitmap_find_and_reset_dirty(mr, offset); + offset = migration_bitmap_find_and_reset_dirty(block, offset); if (complete_round && block == last_seen_block && offset >= last_offset) { break; @@ -1344,7 +1340,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, return NULL; } - return memory_region_get_ram_ptr(block->mr) + offset; + return block->host + offset; } len = qemu_get_byte(f); @@ -1354,7 +1350,7 @@ static inline void *host_from_stream_offset(QEMUFile *f, QLIST_FOREACH_RCU(block, &ram_list.blocks, next) { if (!strncmp(id, block->idstr, sizeof(id)) && block->max_length > offset) { - return memory_region_get_ram_ptr(block->mr) + offset; + return block->host + offset; } } From 09f6c85e39ee9e57bd245adbe6f400d387061707 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Aug 2015 11:51:31 +0100 Subject: [PATCH 3/9] Split out end of migration code from migration_thread The code that gets run at the end of the migration process is getting large, and I'm about to add more for postcopy. Split it into a separate function. Signed-off-by: Dr. David Alan Gilbert Message-Id: <1439463094-5394-3-git-send-email-dgilbert@redhat.com> Reviewed-by: zhanghailiang Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- migration/migration.c | 75 +++++++++++++++++++++++++++---------------- trace-events | 2 ++ 2 files changed, 49 insertions(+), 28 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 662e77e4eb..46bb410ef3 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -913,6 +913,50 @@ int64_t migrate_xbzrle_cache_size(void) return s->xbzrle_cache_size; } +/** + * migration_completion: Used by migration_thread when there's not much left. + * The caller 'breaks' the loop when this returns. + * + * @s: Current migration state + * @*old_vm_running: Pointer to old_vm_running flag + * @*start_time: Pointer to time to update + */ +static void migration_completion(MigrationState *s, bool *old_vm_running, + int64_t *start_time) +{ + int ret; + + qemu_mutex_lock_iothread(); + *start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); + qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); + *old_vm_running = runstate_is_running(); + + ret = global_state_store(); + if (!ret) { + ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); + if (ret >= 0) { + qemu_file_set_rate_limit(s->file, INT64_MAX); + qemu_savevm_state_complete(s->file); + } + } + qemu_mutex_unlock_iothread(); + + if (ret < 0) { + goto fail; + } + + if (qemu_file_get_error(s->file)) { + trace_migration_completion_file_err(); + goto fail; + } + + migrate_set_state(s, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_COMPLETED); + return; + +fail: + migrate_set_state(s, MIGRATION_STATUS_ACTIVE, MIGRATION_STATUS_FAILED); +} + /* migration thread support */ static void *migration_thread(void *opaque) @@ -943,34 +987,9 @@ static void *migration_thread(void *opaque) if (pending_size && pending_size >= max_size) { qemu_savevm_state_iterate(s->file); } else { - int ret; - - qemu_mutex_lock_iothread(); - start_time = qemu_clock_get_ms(QEMU_CLOCK_REALTIME); - qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER); - old_vm_running = runstate_is_running(); - - ret = global_state_store(); - if (!ret) { - ret = vm_stop_force_state(RUN_STATE_FINISH_MIGRATE); - if (ret >= 0) { - qemu_file_set_rate_limit(s->file, INT64_MAX); - qemu_savevm_state_complete(s->file); - } - } - qemu_mutex_unlock_iothread(); - - if (ret < 0) { - migrate_set_state(s, MIGRATION_STATUS_ACTIVE, - MIGRATION_STATUS_FAILED); - break; - } - - if (!qemu_file_get_error(s->file)) { - migrate_set_state(s, MIGRATION_STATUS_ACTIVE, - MIGRATION_STATUS_COMPLETED); - break; - } + trace_migration_thread_low_pending(pending_size); + migration_completion(s, &old_vm_running, &start_time); + break; } } diff --git a/trace-events b/trace-events index a70ea9c3ae..59266e9135 100644 --- a/trace-events +++ b/trace-events @@ -1420,6 +1420,8 @@ migrate_transferred(uint64_t tranferred, uint64_t time_spent, double bandwidth, migrate_state_too_big(void) "" migrate_global_state_post_load(const char *state) "loaded state: %s" migrate_global_state_pre_save(const char *state) "saved state: %s" +migration_completion_file_err(void) "" +migration_thread_low_pending(uint64_t pending) "%" PRIu64 # migration/rdma.c qemu_rdma_accept_incoming_migration(void) "" From c50766f5a99ef7bf6c9a86cd07341c389faf7ae6 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Aug 2015 11:51:32 +0100 Subject: [PATCH 4/9] Init page sizes in qtest One of my patches used a loop that was based on host page size; it dies in qtest since qtest hadn't bothered init'ing it. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Juan Quintela Reviewed-by: Amit Shah Message-Id: <1439463094-5394-4-git-send-email-dgilbert@redhat.com> Signed-off-by: Amit Shah --- qtest.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qtest.c b/qtest.c index 05cefd2800..8e10340c7e 100644 --- a/qtest.c +++ b/qtest.c @@ -657,6 +657,7 @@ void qtest_init(const char *qtest_chrdev, const char *qtest_log, Error **errp) inbuf = g_string_new(""); qtest_chr = chr; + page_size_init(); } bool qtest_driver(void) From a202a4c001fd35b50d99abcc329bc9e666eb8eed Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Aug 2015 11:51:33 +0100 Subject: [PATCH 5/9] migration: size_t'ify some of qemu-file This is a start on using size_t more in qemu-file and friends; it fixes up QEMUFilePutBufferFunc and QEMUFileGetBufferFunc to take size_t lengths and return ssize_t return values (like read(2)) and fixes up all the different implementations of them. Note that I've not yet followed this deeply into bdrv_ implementations. Signed-off-by: Dr. David Alan Gilbert Message-Id: <1439463094-5394-5-git-send-email-dgilbert@redhat.com> Reviewed-by: zhanghailiang Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- include/migration/qemu-file.h | 8 ++++---- migration/qemu-file-buf.c | 7 ++++--- migration/qemu-file-stdio.c | 11 ++++++----- migration/qemu-file-unix.c | 6 ++++-- migration/rdma.c | 13 +++++++------ migration/savevm.c | 7 ++++--- trace-events | 2 +- 7 files changed, 30 insertions(+), 24 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index ea49f33fac..e1e2babcf5 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -31,15 +31,15 @@ * The pos argument can be ignored if the file is only being used for * streaming. The handler should try to write all of the data it can. */ -typedef int (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, - int64_t pos, int size); +typedef ssize_t (QEMUFilePutBufferFunc)(void *opaque, const uint8_t *buf, + int64_t pos, size_t size); /* Read a chunk of data from a file at the given position. The pos argument * can be ignored if the file is only be used for streaming. The number of * bytes actually read should be returned. */ -typedef int (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, - int64_t pos, int size); +typedef ssize_t (QEMUFileGetBufferFunc)(void *opaque, uint8_t *buf, + int64_t pos, size_t size); /* Close a file * diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c index 2de9330ca5..1d9528e674 100644 --- a/migration/qemu-file-buf.c +++ b/migration/qemu-file-buf.c @@ -372,7 +372,8 @@ typedef struct QEMUBuffer { bool qsb_allocated; } QEMUBuffer; -static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static ssize_t buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, + size_t size) { QEMUBuffer *s = opaque; ssize_t len = qsb_get_length(s->qsb) - pos; @@ -387,8 +388,8 @@ static int buf_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) return qsb_get_buffer(s->qsb, pos, len, buf); } -static int buf_put_buffer(void *opaque, const uint8_t *buf, - int64_t pos, int size) +static ssize_t buf_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, size_t size) { QEMUBuffer *s = opaque; diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c index 285068b303..dc91137b9c 100644 --- a/migration/qemu-file-stdio.c +++ b/migration/qemu-file-stdio.c @@ -37,11 +37,11 @@ static int stdio_get_fd(void *opaque) return fileno(s->stdio_file); } -static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, - int size) +static ssize_t stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, + size_t size) { QEMUFileStdio *s = opaque; - int res; + size_t res; res = fwrite(buf, 1, size, s->stdio_file); @@ -51,11 +51,12 @@ static int stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos, return res; } -static int stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static ssize_t stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos, + size_t size) { QEMUFileStdio *s = opaque; FILE *fp = s->stdio_file; - int bytes; + ssize_t bytes; for (;;) { clearerr(fp); diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c index bfbc0861ab..adfe91add1 100644 --- a/migration/qemu-file-unix.c +++ b/migration/qemu-file-unix.c @@ -54,7 +54,8 @@ static int socket_get_fd(void *opaque) return s->fd; } -static int socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static ssize_t socket_get_buffer(void *opaque, uint8_t *buf, int64_t pos, + size_t size) { QEMUFileSocket *s = opaque; ssize_t len; @@ -138,7 +139,8 @@ static ssize_t unix_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, return total; } -static int unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static ssize_t unix_get_buffer(void *opaque, uint8_t *buf, int64_t pos, + size_t size) { QEMUFileSocket *s = opaque; ssize_t len; diff --git a/migration/rdma.c b/migration/rdma.c index 9424834501..be7fd922b8 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -2519,8 +2519,8 @@ static void *qemu_rdma_data_init(const char *host_port, Error **errp) * SEND messages for control only. * VM's ram is handled with regular RDMA messages. */ -static int qemu_rdma_put_buffer(void *opaque, const uint8_t *buf, - int64_t pos, int size) +static ssize_t qemu_rdma_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, size_t size) { QEMUFileRDMA *r = opaque; QEMUFile *f = r->file; @@ -2547,7 +2547,8 @@ static int qemu_rdma_put_buffer(void *opaque, const uint8_t *buf, r->len = MIN(remaining, RDMA_SEND_INCREMENT); remaining -= r->len; - head.len = r->len; + /* Guaranteed to fit due to RDMA_SEND_INCREMENT MIN above */ + head.len = (uint32_t)r->len; head.type = RDMA_CONTROL_QEMU_FILE; ret = qemu_rdma_exchange_send(rdma, &head, data, NULL, NULL, NULL); @@ -2564,7 +2565,7 @@ static int qemu_rdma_put_buffer(void *opaque, const uint8_t *buf, } static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf, - int size, int idx) + size_t size, int idx) { size_t len = 0; @@ -2585,8 +2586,8 @@ static size_t qemu_rdma_fill(RDMAContext *rdma, uint8_t *buf, * RDMA links don't use bytestreams, so we have to * return bytes to QEMUFile opportunistically. */ -static int qemu_rdma_get_buffer(void *opaque, uint8_t *buf, - int64_t pos, int size) +static ssize_t qemu_rdma_get_buffer(void *opaque, uint8_t *buf, + int64_t pos, size_t size) { QEMUFileRDMA *r = opaque; RDMAContext *rdma = r->rdma; diff --git a/migration/savevm.c b/migration/savevm.c index 33e55fea09..96b8210cc3 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -138,14 +138,15 @@ static ssize_t block_writev_buffer(void *opaque, struct iovec *iov, int iovcnt, return qiov.size; } -static int block_put_buffer(void *opaque, const uint8_t *buf, - int64_t pos, int size) +static ssize_t block_put_buffer(void *opaque, const uint8_t *buf, + int64_t pos, size_t size) { bdrv_save_vmstate(opaque, buf, pos, size); return size; } -static int block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, int size) +static ssize_t block_get_buffer(void *opaque, uint8_t *buf, int64_t pos, + size_t size) { return bdrv_load_vmstate(opaque, buf, pos, size); } diff --git a/trace-events b/trace-events index 59266e9135..36db793b47 100644 --- a/trace-events +++ b/trace-events @@ -1442,7 +1442,7 @@ qemu_rdma_exchange_get_response_none(const char *desc, int type) "Surprise: got qemu_rdma_exchange_send_issue_callback(void) "" qemu_rdma_exchange_send_waiting(const char *desc) "Waiting for response %s" qemu_rdma_exchange_send_received(const char *desc) "Response %s received." -qemu_rdma_fill(int64_t control_len, int size) "RDMA %" PRId64 " of %d bytes already in buffer" +qemu_rdma_fill(size_t control_len, size_t size) "RDMA %zd of %zd bytes already in buffer" qemu_rdma_init_ram_blocks(int blocks) "Allocated %d local ram block structures" qemu_rdma_poll_recv(const char *compstr, int64_t comp, int64_t id, int sent) "completion %s #%" PRId64 " received (%" PRId64 ") left %d" qemu_rdma_poll_write(const char *compstr, int64_t comp, int left, uint64_t block, uint64_t chunk, void *local, void *remote) "completions %s (%" PRId64 ") left %d, block %" PRIu64 ", chunk: %" PRIu64 " %p %p" From 56f3835ff1e70df97f843f4a27abdff6b4a2ae77 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 13 Aug 2015 11:51:34 +0100 Subject: [PATCH 6/9] migration: qemu-file more size_t'ifying This time convert the external functions: qemu_get_buffer, qemu_peek_buffer qemu_put_buffer and qemu_put_buffer_async Signed-off-by: Dr. David Alan Gilbert Message-Id: <1439463094-5394-6-git-send-email-dgilbert@redhat.com> Reviewed-by: zhanghailiang Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- include/migration/qemu-file.h | 10 +++++----- migration/qemu-file.c | 22 +++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/include/migration/qemu-file.h b/include/migration/qemu-file.h index e1e2babcf5..29a338d0a9 100644 --- a/include/migration/qemu-file.h +++ b/include/migration/qemu-file.h @@ -126,13 +126,13 @@ int qemu_get_fd(QEMUFile *f); int qemu_fclose(QEMUFile *f); int64_t qemu_ftell(QEMUFile *f); int64_t qemu_ftell_fast(QEMUFile *f); -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size); void qemu_put_byte(QEMUFile *f, int v); /* * put_buffer without copying the buffer. * The buffer should be available till it is sent asynchronously. */ -void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size); +void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size); bool qemu_file_mode_is_not_valid(const char *mode); bool qemu_file_is_writable(QEMUFile *f); @@ -161,8 +161,8 @@ static inline void qemu_put_ubyte(QEMUFile *f, unsigned int v) void qemu_put_be16(QEMUFile *f, unsigned int v); void qemu_put_be32(QEMUFile *f, unsigned int v); void qemu_put_be64(QEMUFile *f, uint64_t v); -int qemu_peek_buffer(QEMUFile *f, uint8_t **buf, int size, size_t offset); -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size); +size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset); +size_t qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size); ssize_t qemu_put_compression_data(QEMUFile *f, const uint8_t *p, size_t size, int level); int qemu_put_qemu_file(QEMUFile *f_des, QEMUFile *f_src); @@ -237,7 +237,7 @@ static inline void qemu_get_8s(QEMUFile *f, uint8_t *pv) } // Signed versions for type safety -static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, int size) +static inline void qemu_put_sbuffer(QEMUFile *f, const int8_t *buf, size_t size) { qemu_put_buffer(f, (const uint8_t *)buf, size); } diff --git a/migration/qemu-file.c b/migration/qemu-file.c index 6bb3dc15cd..b273b1a8ae 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -270,7 +270,7 @@ int qemu_fclose(QEMUFile *f) return ret; } -static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) +static void add_to_iovec(QEMUFile *f, const uint8_t *buf, size_t size) { /* check for adjacent buffer and coalesce them */ if (f->iovcnt > 0 && buf == f->iov[f->iovcnt - 1].iov_base + @@ -286,7 +286,7 @@ static void add_to_iovec(QEMUFile *f, const uint8_t *buf, int size) } } -void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) +void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, size_t size) { if (!f->ops->writev_buffer) { qemu_put_buffer(f, buf, size); @@ -301,9 +301,9 @@ void qemu_put_buffer_async(QEMUFile *f, const uint8_t *buf, int size) add_to_iovec(f, buf, size); } -void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, int size) +void qemu_put_buffer(QEMUFile *f, const uint8_t *buf, size_t size) { - int l; + size_t l; if (f->last_error) { return; @@ -363,10 +363,10 @@ void qemu_file_skip(QEMUFile *f, int size) * return as many as it managed to read (assuming blocking fd's which * all current QEMUFile are) */ -int qemu_peek_buffer(QEMUFile *f, uint8_t **buf, int size, size_t offset) +size_t qemu_peek_buffer(QEMUFile *f, uint8_t **buf, size_t size, size_t offset) { - int pending; - int index; + ssize_t pending; + size_t index; assert(!qemu_file_is_writable(f)); assert(offset < IO_BUF_SIZE); @@ -411,13 +411,13 @@ int qemu_peek_buffer(QEMUFile *f, uint8_t **buf, int size, size_t offset) * return as many as it managed to read (assuming blocking fd's which * all current QEMUFile are) */ -int qemu_get_buffer(QEMUFile *f, uint8_t *buf, int size) +size_t qemu_get_buffer(QEMUFile *f, uint8_t *buf, size_t size) { - int pending = size; - int done = 0; + size_t pending = size; + size_t done = 0; while (pending > 0) { - int res; + size_t res; uint8_t *src; res = qemu_peek_buffer(f, &src, MIN(pending, IO_BUF_SIZE), 0); From 97f3ad35517e0d02c0149637d1bb10713c52b057 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Mon, 14 Sep 2015 13:51:31 +0200 Subject: [PATCH 7/9] migration: Use g_new() & friends where that makes obvious sense g_new(T, n) is neater than g_malloc(sizeof(T) * n). It's also safer, for two reasons. One, it catches multiplication overflowing size_t. Two, it returns T * rather than void *, which lets the compiler catch more type errors. This commit only touches allocations with size arguments of the form sizeof(T). Same Coccinelle semantic patch as in commit b45c03f. Signed-off-by: Markus Armbruster Message-Id: <1442231491-23352-1-git-send-email-armbru@redhat.com> Reviewed-by: Eric Blake Reviewed-by: zhanghailiang Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- migration/migration.c | 2 +- migration/qemu-file-buf.c | 2 +- migration/qemu-file-stdio.c | 4 ++-- migration/qemu-file-unix.c | 4 ++-- migration/qemu-file.c | 2 +- migration/rdma.c | 17 ++++++++--------- migration/savevm.c | 12 ++++++------ 7 files changed, 21 insertions(+), 22 deletions(-) diff --git a/migration/migration.c b/migration/migration.c index 46bb410ef3..e48dd13720 100644 --- a/migration/migration.c +++ b/migration/migration.c @@ -86,7 +86,7 @@ MigrationIncomingState *migration_incoming_get_current(void) MigrationIncomingState *migration_incoming_state_new(QEMUFile* f) { - mis_current = g_malloc0(sizeof(MigrationIncomingState)); + mis_current = g_new0(MigrationIncomingState, 1); mis_current->file = f; QLIST_INIT(&mis_current->loadvm_handlers); diff --git a/migration/qemu-file-buf.c b/migration/qemu-file-buf.c index 1d9528e674..e3fd0859d6 100644 --- a/migration/qemu-file-buf.c +++ b/migration/qemu-file-buf.c @@ -440,7 +440,7 @@ QEMUFile *qemu_bufopen(const char *mode, QEMUSizedBuffer *input) return NULL; } - s = g_malloc0(sizeof(QEMUBuffer)); + s = g_new0(QEMUBuffer, 1); s->qsb = input; if (s->qsb == NULL) { diff --git a/migration/qemu-file-stdio.c b/migration/qemu-file-stdio.c index dc91137b9c..889ffb302c 100644 --- a/migration/qemu-file-stdio.c +++ b/migration/qemu-file-stdio.c @@ -144,7 +144,7 @@ QEMUFile *qemu_popen_cmd(const char *command, const char *mode) return NULL; } - s = g_malloc0(sizeof(QEMUFileStdio)); + s = g_new0(QEMUFileStdio, 1); s->stdio_file = stdio_file; @@ -176,7 +176,7 @@ QEMUFile *qemu_fopen(const char *filename, const char *mode) return NULL; } - s = g_malloc0(sizeof(QEMUFileStdio)); + s = g_new0(QEMUFileStdio, 1); s->stdio_file = fopen(filename, mode); if (!s->stdio_file) { diff --git a/migration/qemu-file-unix.c b/migration/qemu-file-unix.c index adfe91add1..bf7a0e4a2b 100644 --- a/migration/qemu-file-unix.c +++ b/migration/qemu-file-unix.c @@ -194,7 +194,7 @@ QEMUFile *qemu_fdopen(int fd, const char *mode) return NULL; } - s = g_malloc0(sizeof(QEMUFileSocket)); + s = g_new0(QEMUFileSocket, 1); s->fd = fd; if (mode[0] == 'r') { @@ -228,7 +228,7 @@ QEMUFile *qemu_fopen_socket(int fd, const char *mode) return NULL; } - s = g_malloc0(sizeof(QEMUFileSocket)); + s = g_new0(QEMUFileSocket, 1); s->fd = fd; if (mode[0] == 'w') { qemu_set_block(s->fd); diff --git a/migration/qemu-file.c b/migration/qemu-file.c index b273b1a8ae..49addf6d06 100644 --- a/migration/qemu-file.c +++ b/migration/qemu-file.c @@ -60,7 +60,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, const QEMUFileOps *ops) { QEMUFile *f; - f = g_malloc0(sizeof(QEMUFile)); + f = g_new0(QEMUFile, 1); f->opaque = opaque; f->ops = ops; diff --git a/migration/rdma.c b/migration/rdma.c index be7fd922b8..7a7176f7c9 100644 --- a/migration/rdma.c +++ b/migration/rdma.c @@ -541,7 +541,7 @@ static int rdma_add_block(RDMAContext *rdma, const char *block_name, RDMALocalBlock *block; RDMALocalBlock *old = local->block; - local->block = g_malloc0(sizeof(RDMALocalBlock) * (local->nb_blocks + 1)); + local->block = g_new0(RDMALocalBlock, local->nb_blocks + 1); if (local->nb_blocks) { int x; @@ -572,7 +572,7 @@ static int rdma_add_block(RDMAContext *rdma, const char *block_name, bitmap_clear(block->transit_bitmap, 0, block->nb_chunks); block->unregister_bitmap = bitmap_new(block->nb_chunks); bitmap_clear(block->unregister_bitmap, 0, block->nb_chunks); - block->remote_keys = g_malloc0(block->nb_chunks * sizeof(uint32_t)); + block->remote_keys = g_new0(uint32_t, block->nb_chunks); block->is_ram_block = local->init ? false : true; @@ -617,8 +617,8 @@ static int qemu_rdma_init_ram_blocks(RDMAContext *rdma) memset(local, 0, sizeof *local); qemu_ram_foreach_block(qemu_rdma_init_one_block, rdma); trace_qemu_rdma_init_ram_blocks(local->nb_blocks); - rdma->dest_blocks = (RDMADestBlock *) g_malloc0(sizeof(RDMADestBlock) * - rdma->local_ram_blocks.nb_blocks); + rdma->dest_blocks = g_new0(RDMADestBlock, + rdma->local_ram_blocks.nb_blocks); local->init = true; return 0; } @@ -677,8 +677,7 @@ static int rdma_delete_block(RDMAContext *rdma, RDMALocalBlock *block) if (local->nb_blocks > 1) { - local->block = g_malloc0(sizeof(RDMALocalBlock) * - (local->nb_blocks - 1)); + local->block = g_new0(RDMALocalBlock, local->nb_blocks - 1); if (block->index) { memcpy(local->block, old, sizeof(RDMALocalBlock) * block->index); @@ -1164,7 +1163,7 @@ static int qemu_rdma_register_and_get_keys(RDMAContext *rdma, /* allocate memory to store chunk MRs */ if (!block->pmr) { - block->pmr = g_malloc0(block->nb_chunks * sizeof(struct ibv_mr *)); + block->pmr = g_new0(struct ibv_mr *, block->nb_chunks); } /* @@ -2494,7 +2493,7 @@ static void *qemu_rdma_data_init(const char *host_port, Error **errp) InetSocketAddress *addr; if (host_port) { - rdma = g_malloc0(sizeof(RDMAContext)); + rdma = g_new0(RDMAContext, 1); rdma->current_index = -1; rdma->current_chunk = -1; @@ -3400,7 +3399,7 @@ static void *qemu_fopen_rdma(RDMAContext *rdma, const char *mode) return NULL; } - r = g_malloc0(sizeof(QEMUFileRDMA)); + r = g_new0(QEMUFileRDMA, 1); r->rdma = rdma; if (mode[0] == 'w') { diff --git a/migration/savevm.c b/migration/savevm.c index 96b8210cc3..dbcc39a617 100644 --- a/migration/savevm.c +++ b/migration/savevm.c @@ -481,7 +481,7 @@ int register_savevm_live(DeviceState *dev, { SaveStateEntry *se; - se = g_malloc0(sizeof(SaveStateEntry)); + se = g_new0(SaveStateEntry, 1); se->version_id = version_id; se->section_id = savevm_state.global_section_id++; se->ops = ops; @@ -499,7 +499,7 @@ int register_savevm_live(DeviceState *dev, pstrcat(se->idstr, sizeof(se->idstr), "/"); g_free(id); - se->compat = g_malloc0(sizeof(CompatEntry)); + se->compat = g_new0(CompatEntry, 1); pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), idstr); se->compat->instance_id = instance_id == -1 ? calculate_compat_instance_id(idstr) : instance_id; @@ -527,7 +527,7 @@ int register_savevm(DeviceState *dev, LoadStateHandler *load_state, void *opaque) { - SaveVMHandlers *ops = g_malloc0(sizeof(SaveVMHandlers)); + SaveVMHandlers *ops = g_new0(SaveVMHandlers, 1); ops->save_state = save_state; ops->load_state = load_state; return register_savevm_live(dev, idstr, instance_id, version_id, @@ -569,7 +569,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, /* If this triggers, alias support can be dropped for the vmsd. */ assert(alias_id == -1 || required_for_version >= vmsd->minimum_version_id); - se = g_malloc0(sizeof(SaveStateEntry)); + se = g_new0(SaveStateEntry, 1); se->version_id = vmsd->version_id; se->section_id = savevm_state.global_section_id++; se->opaque = opaque; @@ -583,7 +583,7 @@ int vmstate_register_with_alias_id(DeviceState *dev, int instance_id, pstrcat(se->idstr, sizeof(se->idstr), "/"); g_free(id); - se->compat = g_malloc0(sizeof(CompatEntry)); + se->compat = g_new0(CompatEntry, 1); pstrcpy(se->compat->idstr, sizeof(se->compat->idstr), vmsd->name); se->compat->instance_id = instance_id == -1 ? calculate_compat_instance_id(vmsd->name) : instance_id; @@ -1545,7 +1545,7 @@ void hmp_info_snapshots(Monitor *mon, const QDict *qdict) return; } - available_snapshots = g_malloc0(sizeof(int) * nb_sns); + available_snapshots = g_new0(int, nb_sns); total = 0; for (i = 0; i < nb_sns; i++) { sn = &sn_tab[i]; From b8fb8cb748497aa070304eec27b03edd3b05373d Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 23 Sep 2015 15:27:10 +0100 Subject: [PATCH 8/9] Move dirty page search state into separate structure Pull the search state for one iteration of the dirty page search into a structure. Signed-off-by: Dr. David Alan Gilbert Reviewed-by: Amit Shah Message-Id: <1443018431-11170-2-git-send-email-dgilbert@redhat.com> Reviewed-by: Amit Shah Signed-off-by: Amit Shah --- migration/ram.c | 55 +++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index 7df9157ec7..d79d79de1f 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -227,6 +227,17 @@ static uint64_t migration_dirty_pages; static uint32_t last_version; static bool ram_bulk_stage; +/* used by the search for pages to send */ +struct PageSearchStatus { + /* Current block being searched */ + RAMBlock *block; + /* Current offset to search from */ + ram_addr_t offset; + /* Set once we wrap around */ + bool complete_round; +}; +typedef struct PageSearchStatus PageSearchStatus; + struct CompressParam { bool start; bool done; @@ -531,7 +542,6 @@ static void migration_bitmap_sync_range(ram_addr_t start, ram_addr_t length) cpu_physical_memory_sync_dirty_bitmap(bitmap, start, length); } - /* Fix me: there are too many global variables used in migration process. */ static int64_t start_time; static int64_t bytes_xfer_prev; @@ -923,26 +933,30 @@ static int ram_save_compressed_page(QEMUFile *f, RAMBlock *block, static int ram_find_and_save_block(QEMUFile *f, bool last_stage, uint64_t *bytes_transferred) { - RAMBlock *block = last_seen_block; - ram_addr_t offset = last_offset; - bool complete_round = false; + PageSearchStatus pss; int pages = 0; - if (!block) - block = QLIST_FIRST_RCU(&ram_list.blocks); + pss.block = last_seen_block; + pss.offset = last_offset; + pss.complete_round = false; + + if (!pss.block) { + pss.block = QLIST_FIRST_RCU(&ram_list.blocks); + } while (true) { - offset = migration_bitmap_find_and_reset_dirty(block, offset); - if (complete_round && block == last_seen_block && - offset >= last_offset) { + pss.offset = migration_bitmap_find_and_reset_dirty(pss.block, + pss.offset); + if (pss.complete_round && pss.block == last_seen_block && + pss.offset >= last_offset) { break; } - if (offset >= block->used_length) { - offset = 0; - block = QLIST_NEXT_RCU(block, next); - if (!block) { - block = QLIST_FIRST_RCU(&ram_list.blocks); - complete_round = true; + if (pss.offset >= pss.block->used_length) { + pss.offset = 0; + pss.block = QLIST_NEXT_RCU(pss.block, next); + if (!pss.block) { + pss.block = QLIST_FIRST_RCU(&ram_list.blocks); + pss.complete_round = true; ram_bulk_stage = false; if (migrate_use_xbzrle()) { /* If xbzrle is on, stop using the data compression at this @@ -954,23 +968,24 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, } } else { if (compression_switch && migrate_use_compression()) { - pages = ram_save_compressed_page(f, block, offset, last_stage, + pages = ram_save_compressed_page(f, pss.block, pss.offset, + last_stage, bytes_transferred); } else { - pages = ram_save_page(f, block, offset, last_stage, + pages = ram_save_page(f, pss.block, pss.offset, last_stage, bytes_transferred); } /* if page is unmodified, continue to the next */ if (pages > 0) { - last_sent_block = block; + last_sent_block = pss.block; break; } } } - last_seen_block = block; - last_offset = offset; + last_seen_block = pss.block; + last_offset = pss.offset; return pages; } From b9e6092814735853cc1149e2e68245b09f621306 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Wed, 23 Sep 2015 15:27:11 +0100 Subject: [PATCH 9/9] ram_find_and_save_block: Split out the finding Split out the finding of the dirty page and all the wrap detection into a separate function since it was getting a bit hairy. Signed-off-by: Dr. David Alan Gilbert Message-Id: <1443018431-11170-3-git-send-email-dgilbert@redhat.com> Reviewed-by: Amit Shah [Fix comment -- Amit] Signed-off-by: Amit Shah --- migration/ram.c | 84 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/migration/ram.c b/migration/ram.c index d79d79de1f..5187637d45 100644 --- a/migration/ram.c +++ b/migration/ram.c @@ -917,6 +917,59 @@ static int ram_save_compressed_page(QEMUFile *f, RAMBlock *block, return pages; } +/* + * Find the next dirty page and update any state associated with + * the search process. + * + * Returns: True if a page is found + * + * @f: Current migration stream. + * @pss: Data about the state of the current dirty page scan. + * @*again: Set to false if the search has scanned the whole of RAM + */ +static bool find_dirty_block(QEMUFile *f, PageSearchStatus *pss, + bool *again) +{ + pss->offset = migration_bitmap_find_and_reset_dirty(pss->block, + pss->offset); + if (pss->complete_round && pss->block == last_seen_block && + pss->offset >= last_offset) { + /* + * We've been once around the RAM and haven't found anything. + * Give up. + */ + *again = false; + return false; + } + if (pss->offset >= pss->block->used_length) { + /* Didn't find anything in this RAM Block */ + pss->offset = 0; + pss->block = QLIST_NEXT_RCU(pss->block, next); + if (!pss->block) { + /* Hit the end of the list */ + pss->block = QLIST_FIRST_RCU(&ram_list.blocks); + /* Flag that we've looped */ + pss->complete_round = true; + ram_bulk_stage = false; + if (migrate_use_xbzrle()) { + /* If xbzrle is on, stop using the data compression at this + * point. In theory, xbzrle can do better than compression. + */ + flush_compressed_data(f); + compression_switch = false; + } + } + /* Didn't find anything this time, but try again on the new block */ + *again = true; + return false; + } else { + /* Can go around again, but... */ + *again = true; + /* We've found something so probably don't need to */ + return true; + } +} + /** * ram_find_and_save_block: Finds a dirty page and sends it to f * @@ -935,6 +988,7 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, { PageSearchStatus pss; int pages = 0; + bool again, found; pss.block = last_seen_block; pss.offset = last_offset; @@ -944,29 +998,10 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, pss.block = QLIST_FIRST_RCU(&ram_list.blocks); } - while (true) { - pss.offset = migration_bitmap_find_and_reset_dirty(pss.block, - pss.offset); - if (pss.complete_round && pss.block == last_seen_block && - pss.offset >= last_offset) { - break; - } - if (pss.offset >= pss.block->used_length) { - pss.offset = 0; - pss.block = QLIST_NEXT_RCU(pss.block, next); - if (!pss.block) { - pss.block = QLIST_FIRST_RCU(&ram_list.blocks); - pss.complete_round = true; - ram_bulk_stage = false; - if (migrate_use_xbzrle()) { - /* If xbzrle is on, stop using the data compression at this - * point. In theory, xbzrle can do better than compression. - */ - flush_compressed_data(f); - compression_switch = false; - } - } - } else { + do { + found = find_dirty_block(f, &pss, &again); + + if (found) { if (compression_switch && migrate_use_compression()) { pages = ram_save_compressed_page(f, pss.block, pss.offset, last_stage, @@ -979,10 +1014,9 @@ static int ram_find_and_save_block(QEMUFile *f, bool last_stage, /* if page is unmodified, continue to the next */ if (pages > 0) { last_sent_block = pss.block; - break; } } - } + } while (!pages && again); last_seen_block = pss.block; last_offset = pss.offset;