--- tools/libxc/include/xenguest.h | 6 +- tools/libxc/xc_nomigrate.c | 6 +- tools/libxc/xc_sr_common.h | 3 + tools/libxc/xc_sr_restore.c | 14 +++-- tools/libxc/xc_sr_save.c | 118 +++++++++++++++++++++++++++++++++++++- tools/libxc/xc_sr_save_x86_hvm.c | 7 ++- tools/libxc/xc_sr_stream_format.h | 4 ++ 7 files changed, 144 insertions(+), 14 deletions(-)
diff --git a/tools/libxc/include/xenguest.h b/tools/libxc/include/xenguest.h index 5cd8111..a6f52f1 100644 --- a/tools/libxc/include/xenguest.h +++ b/tools/libxc/include/xenguest.h @@ -103,7 +103,8 @@ typedef enum { int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */, struct save_callbacks* callbacks, int hvm, - xc_migration_stream_t stream_type, int recv_fd); + xc_migration_stream_t stream_type, int recv_fd, + int migration_phase); /* callbacks provided by xc_domain_restore */ struct restore_callbacks { @@ -168,7 +169,8 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, unsigned long *console_mfn, domid_t console_domid, unsigned int hvm, unsigned int pae, xc_migration_stream_t stream_type, - struct restore_callbacks *callbacks, int send_back_fd); + struct restore_callbacks *callbacks, int send_back_fd, + int migration_phase); /** * This function will create a domain for a paravirtualized Linux diff --git a/tools/libxc/xc_nomigrate.c b/tools/libxc/xc_nomigrate.c index 317c8ce..c75411b 100644 --- a/tools/libxc/xc_nomigrate.c +++ b/tools/libxc/xc_nomigrate.c @@ -23,7 +23,8 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t max_factor, uint32_t flags, struct save_callbacks* callbacks, int hvm, - xc_migration_stream_t stream_type, int recv_fd) + xc_migration_stream_t stream_type, int recv_fd, + int migration_phase) { errno = ENOSYS; return -1; @@ -35,7 +36,8 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, unsigned long *console_mfn, domid_t console_domid, unsigned int hvm, unsigned int pae, xc_migration_stream_t stream_type, - struct restore_callbacks *callbacks, int send_back_fd) + struct restore_callbacks *callbacks, int send_back_fd, + int migration_phase) { errno = ENOSYS; return -1; diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h index a83f22a..903f18a 100644 --- a/tools/libxc/xc_sr_common.h +++ b/tools/libxc/xc_sr_common.h @@ -96,6 +96,8 @@ struct xc_sr_save_ops * after a successful save, or upon encountering an error. */ int (*cleanup)(struct xc_sr_context *ctx); + + int (*local_disks)(struct xc_sr_context *ctx); }; @@ -177,6 +179,7 @@ struct xc_sr_context xc_interface *xch; uint32_t domid; int fd; + int migration_phase; xc_dominfo_t dominfo; diff --git a/tools/libxc/xc_sr_restore.c b/tools/libxc/xc_sr_restore.c index a016678..13e6abc 100644 --- a/tools/libxc/xc_sr_restore.c +++ b/tools/libxc/xc_sr_restore.c @@ -799,11 +799,13 @@ static int restore(struct xc_sr_context *ctx) * With Remus, if we reach here, there must be some error on primary, * failover from the last checkpoint state. */ - rc = ctx->restore.ops.stream_complete(ctx); - if ( rc ) - goto err; + if ( !ctx->migration_phase != MIGRATION_PHASE_MIRROR_DISK ) { + rc = ctx->restore.ops.stream_complete(ctx); + if ( rc ) + goto err; - IPRINTF("Restore successful"); + IPRINTF("Restore successful"); + } goto done; err: @@ -829,13 +831,15 @@ int xc_domain_restore(xc_interface *xch, int io_fd, uint32_t dom, unsigned long *console_gfn, domid_t console_domid, unsigned int hvm, unsigned int pae, xc_migration_stream_t stream_type, - struct restore_callbacks *callbacks, int send_back_fd) + struct restore_callbacks *callbacks, int send_back_fd, + int migration_phase) { xen_pfn_t nr_pfns; struct xc_sr_context ctx = { .xch = xch, .fd = io_fd, + .migration_phase = migration_phase }; /* GCC 4.4 (of CentOS 6.x vintage) can' t initialise anonymous unions. */ diff --git a/tools/libxc/xc_sr_save.c b/tools/libxc/xc_sr_save.c index ca6913b..181a0c8 100644 --- a/tools/libxc/xc_sr_save.c +++ b/tools/libxc/xc_sr_save.c @@ -412,6 +412,96 @@ static int send_all_pages(struct xc_sr_context *ctx) return send_dirty_pages(ctx, ctx->save.p2m_size); } +static void clear_virtual_devices_memory(struct xc_sr_context *ctx) +{ + xen_pfn_t p; + DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap, + &ctx->save.dirty_bitmap_hbuf); + + for ( p = 0x7800; p < 0xfeff2; p++ ){ + if ( test_bit(p, dirty_bitmap) ){ + clear_bit(p, dirty_bitmap); + } + } + return; +} + +static int send_virtual_ram(struct xc_sr_context *ctx) +{ + DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap, + &ctx->save.dirty_bitmap_hbuf); + + bitmap_set(dirty_bitmap, ctx->save.p2m_size); + + /* + * On the second stream of a migration with local disk, + * don't send the vfb, virtual devices. Only virtual RAM + */ + clear_virtual_devices_memory(ctx); + + return send_dirty_pages(ctx, ctx->save.p2m_size); +} + +static int send_specific_pages(struct xc_sr_context *ctx, uint64_t value) +{ + + int rc = 0; + DECLARE_HYPERCALL_BUFFER_SHADOW(unsigned long, dirty_bitmap, + &ctx->save.dirty_bitmap_hbuf); + + bitmap_clear(dirty_bitmap, ctx->save.p2m_size); + set_bit(value, dirty_bitmap); + + rc = send_dirty_pages(ctx, 1); + bitmap_clear(dirty_bitmap, ctx->save.p2m_size); + return rc; + +} + +static int send_virtual_devices_and_params(struct xc_sr_context *ctx) +{ + xc_interface *xch = ctx->xch; + uint64_t i = 0; + int rc = 0; + + fprintf(stderr, "BRUNO: SEND VIRTUAL DEVICES AND PARAMS\n"); + xc_set_progress_prefix(xch, "Frames"); + + //FOR RTL AND VGA IN 128MB VM . Might change on size of VM + for( i = 0x8000; i < 0x8050; i++ ) + { + rc = send_specific_pages(ctx, i); + if( rc ) + goto out; + } + //VGA + for( i = 0xf0000; i < 0xf0800; i++ ) + { + rc = send_specific_pages(ctx, i); + if( rc ) + goto out; + } + + //Virtual Device + for( i = 0xfc000; i < 0xfc00b; i++ ) + { + rc = send_specific_pages(ctx, i); + if( rc ) + goto out; + } + + for( i = 0xfeff2; i < 0xff000; i++ ) + { + rc = send_specific_pages(ctx, i); + if( rc ) + goto out; + } + + rc = ctx->save.ops.local_disks(ctx); + out: + return rc; +} + static int enable_logdirty(struct xc_sr_context *ctx) { xc_interface *xch = ctx->xch; @@ -481,7 +571,11 @@ static int send_memory_live(struct xc_sr_context *ctx) if ( rc ) goto out; - rc = send_all_pages(ctx); + if ( !ctx->migration_phase ) + rc = send_all_pages(ctx); + else + rc = send_virtual_ram(ctx); + if ( rc ) goto out; @@ -499,6 +593,9 @@ static int send_memory_live(struct xc_sr_context *ctx) goto out; } + if ( ctx->migration_phase ) + clear_virtual_devices_memory(ctx); + if ( stats.dirty_count == 0 ) break; @@ -620,6 +717,9 @@ static int suspend_and_send_dirty(struct xc_sr_context *ctx) } } + if ( ctx->migration_phase ) + clear_virtual_devices_memory(ctx); + rc = send_dirty_pages(ctx, stats.dirty_count + ctx->save.nr_deferred_pages); if ( rc ) goto out; @@ -805,6 +905,14 @@ static int save(struct xc_sr_context *ctx, uint16_t guest_type) if ( rc ) goto err; + /* First pass of QEMU disk migration */ + if ( ctx->migration_phase == MIGRATION_PHASE_MIRROR_DISK ) { + rc = send_virtual_devices_and_params(ctx); + if ( rc ) + goto err; + goto end; + } + rc = ctx->save.ops.start_of_stream(ctx); if ( rc ) goto err; @@ -889,6 +997,7 @@ static int save(struct xc_sr_context *ctx, uint16_t guest_type) } } while ( ctx->save.checkpointed != XC_MIG_STREAM_NONE ); + end: xc_report_progress_single(xch, "End of stream"); rc = write_end_record(ctx); @@ -918,12 +1027,14 @@ static int save(struct xc_sr_context *ctx, uint16_t guest_type) int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, uint32_t max_iters, uint32_t max_factor, uint32_t flags, struct save_callbacks* callbacks, int hvm, - xc_migration_stream_t stream_type, int recv_fd) + xc_migration_stream_t stream_type, int recv_fd, + int migration_phase) { struct xc_sr_context ctx = { .xch = xch, .fd = io_fd, + .migration_phase = migration_phase }; /* GCC 4.4 (of CentOS 6.x vintage) can' t initialise anonymous unions. */ @@ -948,7 +1059,8 @@ int xc_domain_save(xc_interface *xch, int io_fd, uint32_t dom, ctx.save.dirty_threshold = 50; /* Sanity checks for callbacks. */ - if ( hvm ) + /* Now the mirror qemu stream doesn't enable/disable qemu log */ + if ( hvm && ctx.migration_phase != MIGRATION_PHASE_MIRROR_DISK ) assert(callbacks->switch_qemu_logdirty); if ( ctx.save.checkpointed ) assert(callbacks->checkpoint && callbacks->postcopy); diff --git a/tools/libxc/xc_sr_save_x86_hvm.c b/tools/libxc/xc_sr_save_x86_hvm.c index e17bb59..e417da2 100644 --- a/tools/libxc/xc_sr_save_x86_hvm.c +++ b/tools/libxc/xc_sr_save_x86_hvm.c @@ -157,7 +157,8 @@ static int x86_hvm_setup(struct xc_sr_context *ctx) ctx->save.p2m_size = nr_pfns; - if ( ctx->save.callbacks->switch_qemu_logdirty( + if ( ctx->migration_phase != MIGRATION_PHASE_MIRROR_DISK && + ctx->save.callbacks->switch_qemu_logdirty( ctx->domid, 1, ctx->save.callbacks->data) ) { PERROR("Couldn't enable qemu log-dirty mode"); @@ -214,7 +215,8 @@ static int x86_hvm_cleanup(struct xc_sr_context *ctx) xc_interface *xch = ctx->xch; /* If qemu successfully enabled logdirty mode, attempt to disable. */ - if ( ctx->x86_hvm.save.qemu_enabled_logdirty && + if ( ctx->migration_phase != MIGRATION_PHASE_MIRROR_DISK && + ctx->x86_hvm.save.qemu_enabled_logdirty && ctx->save.callbacks->switch_qemu_logdirty( ctx->domid, 0, ctx->save.callbacks->data) ) { @@ -235,6 +237,7 @@ struct xc_sr_save_ops save_ops_x86_hvm = .end_of_checkpoint = x86_hvm_end_of_checkpoint, .check_vm_state = x86_hvm_check_vm_state, .cleanup = x86_hvm_cleanup, + .local_disks = x86_hvm_end_of_checkpoint, }; /* diff --git a/tools/libxc/xc_sr_stream_format.h b/tools/libxc/xc_sr_stream_format.h index 15ff1c7..1f0b274 100644 --- a/tools/libxc/xc_sr_stream_format.h +++ b/tools/libxc/xc_sr_stream_format.h @@ -8,6 +8,10 @@ #include <inttypes.h> +#define MIGRATION_PHASE_NON_LOCAL_DISK 0 +#define MIGRATION_PHASE_VIRTUAL_RAM 1 +#define MIGRATION_PHASE_MIRROR_DISK 2 + /* * Image Header */ -- 2.3.2 (Apple Git-55) _______________________________________________ Xen-devel mailing list Xen-devel@lists.xen.org https://lists.xen.org/xen-devel