# HG changeset patch # User David Scott # Date 1263336663 0 # Node ID aacf1b563353749ebb9d6f0d8b89327de784bcdf # Parent 7ec163e4ed6c8efd53e3996a2e58abaf0213aec5 CA-36384: [experimental PCI passthrough]: Make reboot + PCI passthrough use the devices in Device.PCI.list rather than new values from the VM record. This makes internal reboot keep the PCI device: previously the attempt to read the new value would fail the RBAC permission check. The only downside of this is that to change the PCI device, you have to shutdown and restart. Signed-off-by: David Scott diff -r 7ec163e4ed6c -r aacf1b563353 ocaml/xapi/vmops.ml --- a/ocaml/xapi/vmops.ml Tue Jan 12 22:51:03 2010 +0000 +++ b/ocaml/xapi/vmops.ml Tue Jan 12 22:51:03 2010 +0000 @@ -115,13 +115,24 @@ raise (Api_errors.Server_error (Api_errors.cannot_plug_vif, [ Ref.string_of vif.Vm_config.vif_ref ])) ) vifs +let sort_pcidevs devs = + let ids = ref [] in + List.iter (fun (id, _) -> + if not (List.mem id !ids) then + ids := id :: !ids + ) devs; + + List.map (fun id -> + id, (List.map snd (List.filter (fun (x, _) -> x = id) devs)) + ) !ids + let attach_pcis ~__context ~xc ~xs ~hvm domid pcis = Helpers.log_exn_continue "attach_pcis" (fun () -> List.iter (fun (devid, devs) -> Device.PCI.bind devs; Device.PCI.add ~xc ~xs ~hvm ~msitranslate:0 ~pci_power_mgmt:0 devs domid devid - ) pcis + ) (sort_pcidevs pcis) ) () (* Called on both VM.start and VM.resume codepaths to create vcpus in xenstore *) @@ -478,18 +489,9 @@ (fun id a b c d -> (id, (a, b, c, d))) :: acc with _ -> acc ) [] devs in - let ids = ref [] in - List.iter (fun (id, _) -> - if not (List.mem id !ids) then - ids := id :: !ids - ) devs; - let pcidevs = - List.map (fun id -> - id, (List.map snd (List.filter (fun (x, _) -> x = id) devs)) - ) !ids in - if pcidevs <> [] + if devs <> [] then Rbac.assert_permission ~__context ~permission:Rbac_static.permission_internal_vm_plug_pcidevs; - pcidevs + devs (* Hotplug the PCI devices into the domain (as opposed to 'attach_pcis') *) let plug_pcidevs ~__context ~vm domid pcidevs = @@ -508,7 +510,7 @@ debug "hotplugging PCI device %04x:%02x:%02x.%01x into domid: %d" a b c d domid; Device.PCI.plug ~xc ~xs device domid devid ) devices - ) pcidevs + ) (sort_pcidevs pcidevs) end ) end; @@ -916,7 +918,7 @@ (** Starts up a VM, leaving it in the paused state *) -let start_paused ?(progress_cb = fun _ -> ()) ~__context ~vm ~snapshot = +let start_paused ?(progress_cb = fun _ -> ()) ~pcidevs ~__context ~vm ~snapshot = check_vm_parameters ~__context ~self:vm ~snapshot; (* Take the subset of locked VBDs *) let other_config = Db.VM.get_other_config ~__context ~self:vm in @@ -970,6 +972,9 @@ if Xapi_globs.xenclient_enabled then Domain.cpuid_apply ~xc ~hvm domid; + (* XXX: PCI passthrough needs a lot of work *) + let pcidevs = (match pcidevs with Some x -> x | None -> pcidevs_of_vm ~__context ~vm) in + (* Don't attempt to attach empty VBDs to PV guests: they can't handle them *) let vbds = if hvm then vbds @@ -1002,9 +1007,8 @@ let vifs = Vm_config.vifs_of_vm ~__context ~vm domid in create_vifs ~__context ~xs vifs; progress_cb 0.70; - (* XXX: PCI passthrough needs a lot of work *) if not hvm - then attach_pcis ~__context ~xc ~xs ~hvm domid (pcidevs_of_vm ~__context ~vm); + then attach_pcis ~__context ~xc ~xs ~hvm domid pcidevs; if (Xapi_globs.xenclient_enabled) && (not hvm) && (has_platform_flag snapshot.API.vM_platform "pv_qemu") then @@ -1014,7 +1018,7 @@ progress_cb 0.80; debug "creating device emulator"; let vncport = create_device_emulator ~__context ~xc ~xs ~self:vm domid vifs snapshot in - if hvm then plug_pcidevs ~__context ~vm domid (pcidevs_of_vm ~__context ~vm); + if hvm then plug_pcidevs ~__context ~vm domid pcidevs; create_console ~__context ~vM:vm ~vncport (); debug "writing memory policy"; write_memory_policy ~xs snapshot domid; diff -r 7ec163e4ed6c -r aacf1b563353 ocaml/xapi/xapi_vm.ml --- a/ocaml/xapi/xapi_vm.ml Tue Jan 12 22:51:03 2010 +0000 +++ b/ocaml/xapi/xapi_vm.ml Tue Jan 12 22:51:03 2010 +0000 @@ -248,7 +248,7 @@ debug "start: bringing up domain in the paused state"; Vmops.start_paused - ~progress_cb:(TaskHelper.set_progress ~__context) ~__context ~vm ~snapshot; + ~progress_cb:(TaskHelper.set_progress ~__context) ~pcidevs:None ~__context ~vm ~snapshot; delete_guest_metrics ~__context ~self:vm; let localhost = Helpers.get_localhost ~__context in @@ -400,6 +400,9 @@ else new_snapshot.API.vM_memory_static_max (* new value is smaller *) in let new_snapshot = { new_snapshot with API.vM_memory_static_max = new_mem } in + (* Before we destroy the old domain we check which PCI devices were plugged in *) + let pcidevs = with_xc_and_xs (fun xc xs -> Device.PCI.list xc xs domid) in + let localhost = Helpers.get_localhost ~__context in debug "%s phase 1/3: destroying old domain" api_call_name; (* CA-13585: prevent glitch where power-state goes to Halted in the middle of a reboot. @@ -426,6 +429,7 @@ try Vmops.start_paused ~progress_cb:(fun x -> TaskHelper.set_progress ~__context (0.50 +. x /. 2.)) + ~pcidevs:(Some pcidevs) ~__context ~vm ~snapshot:new_snapshot; with e -> debug "Vmops.start_paused failed to create domain, setting VM %s to Halted" (Ref.string_of vm); diff -r 7ec163e4ed6c -r aacf1b563353 ocaml/xenops/device.ml --- a/ocaml/xenops/device.ml Tue Jan 12 22:51:03 2010 +0000 +++ b/ocaml/xenops/device.ml Tue Jan 12 22:51:03 2010 +0000 @@ -1184,6 +1184,7 @@ int_of_string (String.sub x (String.length prefix) (String.length x - (String.length prefix))) in List.map (fun (x, y) -> device_number_of_string x, of_string y) pairs + let plug ~xc ~xs (domain, bus, dev, func) domid devid = let current = list ~xc ~xs domid in let next_idx = List.fold_left max (-1) (List.map fst current) + 1 in