Permalink
Browse files

CA-77175: Enable resume of VMs suspended on pre-xenopsd hosts.

When resuming a VM, try to parse its last_booted_record according the
old S-expression format. If this succeeds, use the new xenops function
generate_state_string to convert the VM metadata into a new-format
xenops state, which xenopsd can use to resume the VM.

Signed-off-by: John Else <john.else@citrix.com>
  • Loading branch information...
1 parent a605964 commit e3699c45496eff01bca86afce1efb444a0cc927a @johnelse committed May 3, 2012
View
@@ -372,17 +372,33 @@ open Xenops_interface
open Xenops_client
open Fun
+(* If a VM was suspended pre-xenopsd it won't have a last_booted_record of the format understood by xenopsd. *)
+(* If we can parse the last_booted_record according to the old syntax, update it before attempting to resume. *)
+let generate_xenops_state ~__context ~self ~vm ~vbds ~pcis =
+ try
+ let vm_to_resume = {
+ (Helpers.parse_boot_record vm.API.vM_last_booted_record) with
+ API.vM_VBDs = vm.API.vM_VBDs
+ } in
+ debug "Successfully parsed old last_booted_record format - translating to new format so that xenopsd can resume the VM.";
+ let md = MD.of_vm ~__context (self, vm_to_resume) vbds (pcis <> []) in
+ let dbg = Context.string_of_task __context in
+ Client.VM.generate_state_string dbg md
+ with Xml.Error _ ->
+ debug "last_booted_record is not of the old format, so we should be able to resume the VM.";
+ vm.API.vM_last_booted_record
+
(* Create an instance of Metadata.t, suitable for uploading to the xenops service *)
let create_metadata ~__context ~self =
let vm = Db.VM.get_record ~__context ~self in
let vbds = List.map (fun self -> Db.VBD.get_record ~__context ~self) vm.API.vM_VBDs in
let vifs = List.map (fun self -> Db.VIF.get_record ~__context ~self) vm.API.vM_VIFs in
- (* XXX PR-1255: need to convert between 'domains' and last_boot_record *)
+ let pcis = MD.pcis_of_vm ~__context (self, vm) in
let domains =
+ (* For suspended VMs, we may need to translate the last_booted_record from the old format. *)
if vm.API.vM_power_state = `Suspended
- then Some vm.API.vM_last_booted_record
+ then Some (generate_xenops_state ~__context ~self ~vm ~vbds ~pcis)
else None in
- let pcis = MD.pcis_of_vm ~__context (self, vm) in
let open Metadata in {
vm = MD.of_vm ~__context (self, vm) vbds (pcis <> []);
vbds = List.map (fun vbd -> MD.of_vbd ~__context ~vm ~vbd) vbds;
@@ -368,6 +368,7 @@ module VM = struct
external s3suspend: debug_info -> Vm.id -> Task.id = ""
external s3resume: debug_info -> Vm.id -> Task.id = ""
+ external generate_state_string: debug_info -> Vm.t -> string = ""
external export_metadata: debug_info -> Vm.id -> string = ""
external import_metadata: debug_info -> string -> Vm.id = ""
end
@@ -1500,6 +1500,10 @@ module VM = struct
let migrate context dbg id vdi_map vif_map url = queue_operation dbg id (VM_migrate (id, vdi_map, vif_map, url))
+ let generate_state_string _ dbg vm =
+ let module B = (val get_backend () : S) in
+ B.VM.generate_state_string vm
+
let export_metadata _ dbg id = export_metadata [] [] id
let import_metadata _ dbg s =
@@ -85,6 +85,7 @@ module type S = sig
val set_domain_action_request: Vm.t -> domain_action_request option -> unit
val get_domain_action_request: Vm.t -> domain_action_request option
+ val generate_state_string: Vm.t -> string
val get_internal_state: (string * string) list -> (string * Network.t) list -> Vm.t -> string
val set_internal_state: Vm.t -> string -> unit
@@ -341,6 +341,7 @@ module VM = struct
let set_domain_action_request vm request = ()
let get_domain_action_request vm = Mutex.execute m (get_domain_action_request_nolock vm)
+ let generate_state_string vm = ""
let get_internal_state vdi_map vif_map vm =
let state = Opt.unbox (DB.read vm.Vm.id) in
let vbds = List.map (fun vbd -> {vbd with Vbd.backend = Opt.map (remap_vdi vdi_map) vbd.Vbd.backend}) state.Domain.vbds in
@@ -536,6 +536,39 @@ module VM = struct
let get_initial_target ~xs domid =
Int64.of_string (xs.Xs.read (Printf.sprintf "/local/domain/%d/memory/initial-target" domid))
+ (* Called from a xenops client if it needs to resume a VM that was suspended on a pre-xenopsd host. *)
+ let generate_state_string vm =
+ let open Memory in
+ let builder_spec_info =
+ match vm.ty with
+ | HVM hvm_info ->
+ Domain.BuildHVM {
+ Domain.shadow_multiplier = hvm_info.shadow_multiplier;
+ timeoffset = hvm_info.timeoffset;
+ video_mib = hvm_info.video_mib;
+ }
+ | PV { boot = Direct direct } ->
+ Domain.BuildPV {
+ Domain.cmdline = direct.cmdline;
+ ramdisk = direct.ramdisk;
+ }
+ | PV { boot = Indirect { devices = [] } } ->
+ raise (No_bootable_device)
+ | PV { boot = Indirect ( { devices = d :: _ } ) } ->
+ Domain.BuildPV {
+ Domain.cmdline = "";
+ ramdisk = None;
+ }
+ in
+ let build_info = {
+ Domain.memory_max = vm.memory_static_max /// 1024L;
+ memory_target = vm.memory_dynamic_min /// 1024L;
+ kernel = "";
+ vcpus = vm.vcpu_max;
+ priv = builder_spec_info;
+ } in
+ { VmExtra.build_info = Some build_info; ty = Some vm.ty } |> VmExtra.rpc_of_persistent_t |> Jsonrpc.to_string
+
let generate_non_persistent_state xc xs vm =
let hvm = match vm.ty with HVM _ -> true | _ -> false in
(* XXX add per-vcpu information to the platform data *)

0 comments on commit e3699c4

Please sign in to comment.