# HG changeset patch
# User David Scott <dave.scott@xxxxxxxxxxxxx>
# Date 1268739133 0
# Node ID bd84ea5e1a08e0d8019f8ab64a67b96a3a543548
# Parent 012936d9d680683cd83cdcd2cd772985de142c50
CA-37332: move essential suspend/resume-related code (specifically memory and
PCI device handling) into Vmops so that it can be shared with checkpoint.
Signed-off-by: David Scott <dave.scott@xxxxxxxxxxxxx>
diff -r 012936d9d680 -r bd84ea5e1a08 ocaml/xapi/vmops.ml
--- a/ocaml/xapi/vmops.ml Tue Mar 16 11:30:25 2010 +0000
+++ b/ocaml/xapi/vmops.ml Tue Mar 16 11:32:13 2010 +0000
@@ -748,13 +748,19 @@
(** Get the suspend VDI, mount the disk, open the file and call _restore*.
Guarantees to
always unmount the VDI and, only if the restore succeeds, deletes the VDI
(otherwise
an exception from lower-level code propagates out *)
-let restore ~__context ~xc ~xs ~self domid =
+let restore ~__context ~xc ~xs ~self start_paused =
+ let memory_required_kib = Memory.kib_of_bytes_used
(Memory_check.vm_compute_resume_memory ~__context self) in
+ let snapshot = Helpers.get_boot_record ~__context ~self in
+ (* CA-31759: we always use the live memory_target *)
+ let snapshot = { snapshot with API.vM_memory_target =
Db.VM.get_memory_target ~__context ~self } in
+
+ let reservation_id = Memory_control.reserve_memory ~__context ~xc ~xs
~kib:memory_required_kib in
+ let domid = create ~__context ~xc ~xs ~self ~reservation_id snapshot () in
+
Xapi_xenops_errors.handle_xenops_error
(fun () ->
let suspend_vdi = Db.VM.get_suspend_VDI ~__context ~self in
- let snapshot = Helpers.get_boot_record ~__context ~self in
- (* CA-31759: we always use the live memory_target *)
- let snapshot = { snapshot with API.vM_memory_target =
Db.VM.get_memory_target ~__context ~self } in
+
Sm_fs_ops.with_fs_vdi __context suspend_vdi
(fun mount_point ->
@@ -806,7 +812,13 @@
Helpers.call_api_functions ~__context
(fun rpc session_id ->
Client.VDI.destroy rpc session_id suspend_vdi);
- Db.VM.set_suspend_VDI ~__context ~self ~value:Ref.null
+ Db.VM.set_suspend_VDI ~__context ~self ~value:Ref.null;
+
+ Db.VM.set_domid ~__context ~self ~value:(Int64.of_int domid);
+
+ debug "Vmops.restore: %s unpausing domain" (if start_paused then
"not" else "");
+ if not start_paused then Domain.unpause ~xc domid;
+ plug_pcidevs_noexn ~__context ~vm:self domid (pcidevs_of_vm
~__context ~vm:self);
)
@@ -879,10 +891,33 @@
exception Domain_architecture_not_supported_in_suspend
let suspend ~live ~progress_cb ~__context ~xc ~xs ~vm =
- Xapi_xenops_errors.handle_xenops_error
- (fun () ->
- let uuid = Db.VM.get_uuid ~__context ~self:vm in
- let hvm = Helpers.has_booted_hvm ~__context ~self:vm in
+ let uuid = Db.VM.get_uuid ~__context ~self:vm in
+ let hvm = Helpers.has_booted_hvm ~__context ~self:vm in
+ let domid = Helpers.domid_of_vm ~__context ~self:vm in
+
+ Xapi_xenops_errors.handle_xenops_error
+ (fun () ->
+ with_xc_and_xs
+ (fun xc xs ->
+ let is_paused = Db.VM.get_power_state
+ ~__context ~self:vm = `Paused in
+ if is_paused then Domain.unpause ~xc
domid;
+ let min = Db.VM.get_memory_dynamic_min
~__context ~self:vm in
+ let max = Db.VM.get_memory_dynamic_max
~__context ~self:vm in
+ let min = Int64.to_int (Int64.div min
1024L) in
+ let max = Int64.to_int (Int64.div max
1024L) in
+ try
+ (* Balloon down the guest as far as
we can to force it to clear
+ unnecessary caches etc. *)
+ debug "suspend phase 0/4:
asking guest to balloon down";
+ Domain.set_memory_dynamic_range
~xs ~min ~max:min domid;
+ Memory_control.balance_memory
~__context ~xc ~xs;
+
+ debug "suspend phase 1/4:
hot-unplugging any PCI devices";
+ let hvm = (Xc.domain_getinfo xc
domid).Xc.hvm_guest in
+ if hvm then
unplug_pcidevs_noexn ~__context ~vm domid (Device.PCI.list xc xs domid);
+
+
let suspend_SR = Helpers.choose_suspend_sr ~__context
~vm in
let required_space = get_suspend_space __context vm in
Sm_fs_ops.with_new_fs_vdi __context
@@ -891,7 +926,7 @@
~sm_config:[Xapi_globs._sm_vm_hint, uuid]
(fun vdi_ref mount_point ->
let filename = sprintf
"%s/suspend-image" mount_point in
- debug "suspend: phase 1/2: opening
suspend image file (%s)"
+ debug "suspend: phase 2/4: opening
suspend image file (%s)"
filename;
(* NB if the suspend file already
exists it will be *)
(* overwritten. *)
@@ -900,7 +935,7 @@
finally
(fun () ->
let domid =
Helpers.domid_of_vm ~__context ~self:vm in
- debug "suspend: phase
2/2: suspending to disk";
+ debug "suspend: phase
3/4: suspending to disk";
with_xal
(fun xal ->
Domain.suspend ~xc ~xs ~hvm domid fd []
@@ -926,8 +961,25 @@
~value:vdi_ref;
)
(fun () -> Unix.close fd);
- debug "suspend: complete")
- )
+ debug "suspend: complete");
+
+ debug "suspend phase 4/4: recording memory usage";
+ (* Record the final memory usage of the VM, so *)
+ (* that we know how much memory to free before *)
+ (* attempting to resume this VM in future. *)
+ let di = with_xc (fun xc -> Xc.domain_getinfo xc domid)
in
+ let final_memory_bytes = Memory.bytes_of_pages
(Int64.of_nativeint di.Xc.total_memory_pages) in
+ debug "total_memory_pages=%Ld; storing target=%Ld"
(Int64.of_nativeint di.Xc.total_memory_pages) final_memory_bytes;
+ (* CA-31759: avoid using the LBR to simplify upgrade *)
+ Db.VM.set_memory_target ~__context ~self:vm
~value:final_memory_bytes;
+
+ with e ->
+ Domain.set_memory_dynamic_range ~xs ~min ~max domid;
+ Memory_control.balance_memory ~__context ~xc ~xs;
+ if is_paused then
+ (try Domain.pause ~xc domid with _ -> ());
+ raise e
+ ))
let resume ~__context ~xc ~xs ~vm =
let domid = Helpers.domid_of_vm ~__context ~self:vm in
diff -r 012936d9d680 -r bd84ea5e1a08 ocaml/xapi/xapi_vm.ml
--- a/ocaml/xapi/xapi_vm.ml Tue Mar 16 11:30:25 2010 +0000
+++ b/ocaml/xapi/xapi_vm.ml Tue Mar 16 11:32:13 2010 +0000
@@ -724,24 +724,6 @@
~reason:Xapi_hooks.reason__suspend ~vm;
with_xc_and_xs
(fun xc xs ->
- let is_paused = Db.VM.get_power_state
- ~__context ~self:vm = `Paused in
- if is_paused then Domain.unpause ~xc
domid;
- let min = Db.VM.get_memory_dynamic_min
~__context ~self:vm in
- let max = Db.VM.get_memory_dynamic_max
~__context ~self:vm in
- let min = Int64.to_int (Int64.div min
1024L) in
- let max = Int64.to_int (Int64.div max
1024L) in
- try
- (* Balloon down the guest as
far as we can to force it to clear
- unnecessary caches etc. *)
- debug "suspend phase 0/4:
asking guest to balloon down";
- Domain.set_memory_dynamic_range
~xs ~min ~max:min domid;
- Memory_control.balance_memory
~__context ~xc ~xs;
-
- debug "suspend phase 1/4:
hot-unplugging any PCI devices";
- let hvm = (Xc.domain_getinfo xc
domid).Xc.hvm_guest in
- if hvm then
Vmops.unplug_pcidevs_noexn ~__context ~vm domid (Device.PCI.list xc xs domid);
-
debug "suspend phase 2/4:
calling Vmops.suspend";
(* Call the memory image
creating 90%, *)
(* the device un-hotplug the
final 10% *)
@@ -750,24 +732,10 @@
TaskHelper.set_progress
~__context (x
*. 0.9)
);
- debug "suspend phase 3/4:
recording memory usage";
- (* Record the final memory
usage of the VM, so *)
- (* that we know how much memory
to free before *)
- (* attempting to resume this VM
in future. *)
- let di = with_xc (fun xc ->
Xc.domain_getinfo xc domid) in
- let final_memory_bytes =
Memory.bytes_of_pages (Int64.of_nativeint di.Xc.total_memory_pages) in
- debug "total_memory_pages=%Ld;
storing target=%Ld" (Int64.of_nativeint di.Xc.total_memory_pages)
final_memory_bytes;
- (* CA-31759: avoid using the
LBR to simplify upgrade *)
- Db.VM.set_memory_target
~__context ~self:vm ~value:final_memory_bytes;
debug "suspend phase 4/4:
destroying the domain";
Vmops.destroy
~clear_currently_attached:false
~__context ~xc ~xs
~self:vm domid `Suspended;
- with e ->
- Domain.set_memory_dynamic_range
~xs ~min ~max domid;
- Memory_control.balance_memory
~__context ~xc ~xs;
- if is_paused then
- (try Domain.pause ~xc
domid with _ -> ());
- raise e
+
)
)
) ()
@@ -789,37 +757,13 @@
debug "resume: making sure the
VM really is suspended";
assert_power_state_is
~__context ~vm ~expected:`Suspended;
assert_ha_always_run_is_true
~__context ~vm;
- let snapshot =
Helpers.get_boot_record ~__context ~self:vm in
- let memory_required_kib =
-
Memory.kib_of_bytes_used (
-
Memory_check.vm_compute_resume_memory
- ~__context vm)
in
-(*
- Vmops.with_enough_memory
~__context ~xc ~xs ~memory_required_kib
- (fun () ->
-*)
- debug "resume phase 0/3:
allocating memory";
- let reservation_id =
Memory_control.reserve_memory ~__context ~xc ~xs ~kib:memory_required_kib in
- debug "resume phase
1/3: creating an empty domain";
- let domid =
Vmops.create ~__context ~xc ~xs ~self:vm ~reservation_id
- snapshot () in
- debug "resume phase
2/3: executing Vmops.restore";
+
(* vmops.restore
guarantees that, if an exn occurs *)
(* during execution,
any disks that were attached/ *)
(* activated have been
detached/de-activated and *)
(* the domain is
destroyed. *)
- Vmops.restore
~__context ~xc ~xs ~self:vm domid;
- Db.VM.set_domid
~__context ~self:vm
-
~value:(Int64.of_int domid);
-
- debug "resume phase
3/3: %s unpausing domain"
- (if
start_paused then "not" else "");
- if not start_paused
then begin
- Domain.unpause
~xc domid;
- end;
-
-
Vmops.plug_pcidevs_noexn ~__context ~vm domid (Vmops.pcidevs_of_vm ~__context
~vm);
+ Vmops.restore
~__context ~xc ~xs ~self:vm start_paused;
(* VM is now resident
here *)
let localhost =
Helpers.get_localhost ~__context in
2 files changed, 68 insertions(+), 72 deletions(-)
ocaml/xapi/vmops.ml | 78 ++++++++++++++++++++++++++++++++++++++++---------
ocaml/xapi/xapi_vm.ml | 62 +-------------------------------------
xen-api.hg.patch
Description: Text Data
_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api
|