Skip to content

Commit

Permalink
Allow domain 0 to use 256 VBD devices by creating a separate limit ju…
Browse files Browse the repository at this point in the history
…st for it.

Also unify the code in xapi_vbd_helpers and xapi_vm_helpers which dealt with translating VBD userdevices to devices.

Signed-off-by: David Scott <dave.scott@eu.citrix.com>
  • Loading branch information
David Scott committed May 19, 2011
1 parent 78512b0 commit 1a8307d
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 76 deletions.
23 changes: 6 additions & 17 deletions ocaml/xapi/xapi_vbd_helpers.ml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -293,7 +293,7 @@ let create ~__context ~vM ~vDI ~userdevice ~bootable ~mode ~_type ~unpluggable


(* Resolve the "autodetect" into a fixed device name now *) (* Resolve the "autodetect" into a fixed device name now *)
let userdevice = if userdevice = "autodetect" let userdevice = if userdevice = "autodetect"
then List.hd possibilities (* already checked for [] above *) then string_of_int (Device_number.to_disk_number (List.hd possibilities)) (* already checked for [] above *)
else userdevice in else userdevice in


let uuid = Uuid.make_uuid () in let uuid = Uuid.make_uuid () in
Expand All @@ -302,22 +302,11 @@ let create ~__context ~vM ~vDI ~userdevice ~bootable ~mode ~_type ~unpluggable
userdevice (Uuid.string_of_uuid uuid) (Ref.string_of ref); userdevice (Uuid.string_of_uuid uuid) (Ref.string_of ref);


(* Check that the device is definitely unique. If the requested device is numerical (* Check that the device is definitely unique. If the requested device is numerical
(eg 1) then we 'expand' it into other possible names (eg 'hdb' 'xvdb') to detect (eg 1) then we 'expand' it into other possible names (eg 'hdb' 'xvdb') to detect
all possible clashes. *) all possible clashes. *)
let all = Db.VM.get_VBDs ~__context ~self:vM in let userdevices = Xapi_vm_helpers.possible_VBD_devices_of_string userdevice in

let existing_devices = Xapi_vm_helpers.all_used_VBD_devices ~__context ~self:vM in
let existing_devices = if Listext.List.intersect userdevices existing_devices <> []
let all_devices = List.map (fun self -> Db.VBD.get_device ~__context ~self) all in
let all_devices2 = List.map (fun self -> Db.VBD.get_userdevice ~__context ~self) all in
all_devices @ all_devices2 in

let expand s =
(* NB userdevice fields are arbitrary strings and device fields
may be "" *)
let parse hvm x = try Some (Device_number.of_string hvm x) with _ -> None in
Listext.List.unbox_list [ parse true s; parse false s ] in

if Listext.List.intersect (expand userdevice) (List.concat (List.map expand existing_devices)) <> []
then raise (Api_errors.Server_error (Api_errors.device_already_exists, [userdevice])); then raise (Api_errors.Server_error (Api_errors.device_already_exists, [userdevice]));


(* Make people aware that non-shared disks make VMs not agile *) (* Make people aware that non-shared disks make VMs not agile *)
Expand Down
2 changes: 1 addition & 1 deletion ocaml/xapi/xapi_vm.ml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1146,7 +1146,7 @@ let get_possible_hosts ~__context ~vm = Locking_helpers.with_lock vm (fun token
get_possible_hosts_for_vm ~__context ~vm ~snapshot get_possible_hosts_for_vm ~__context ~vm ~snapshot
) () ) ()


let get_allowed_VBD_devices = allowed_VBD_devices let get_allowed_VBD_devices ~__context ~vm = List.map (fun d -> string_of_int (Device_number.to_disk_number d)) (allowed_VBD_devices ~__context ~vm)
let get_allowed_VIF_devices = allowed_VIF_devices let get_allowed_VIF_devices = allowed_VIF_devices


(** Mark all currently-attached VBDs and VIFs as reserved, call some function and then (** Mark all currently-attached VBDs and VIFs as reserved, call some function and then
Expand Down
101 changes: 43 additions & 58 deletions ocaml/xapi/xapi_vm_helpers.ml
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -861,75 +861,60 @@ let send_sysrq ~__context ~vm ~key =
let send_trigger ~__context ~vm ~trigger = let send_trigger ~__context ~vm ~trigger =
raise (Api_errors.Server_error (Api_errors.not_implemented, [ "send_trigger" ])) raise (Api_errors.Server_error (Api_errors.not_implemented, [ "send_trigger" ]))


let range_inclusive a b = let inclusive_range a b = Range.to_list (Range.make a (b + 1))
let rec f a b = if a = b then [ a ] else a :: (f (a + 1) b) in let vbd_inclusive_range hvm a b =
List.map string_of_int (f a b) List.map (Device_number.of_disk_number hvm) (inclusive_range a b)
let vif_inclusive_range a b =
List.map string_of_int (inclusive_range a b)


(* These are high-watermark limits as documented in CA-6525. Individual guest types (* These are high-watermark limits as documented in CA-6525. Individual guest types
may be further restricted. *) may be further restricted. *)


let allowed_VBD_devices_HVM = range_inclusive 0 3 let allowed_VBD_devices_HVM = vbd_inclusive_range true 0 3
let allowed_VBD_devices_HVM_PP = vbd_inclusive_range true 0 15
let allowed_VBD_devices_PV = vbd_inclusive_range false 0 15
let allowed_VBD_devices_control_domain = vbd_inclusive_range false 0 255


let allowed_VBD_devices_HVM_PP = range_inclusive 0 256 let allowed_VIF_devices_HVM = vif_inclusive_range 0 3
let allowed_VIF_devices_HVM_PP = vif_inclusive_range 0 6
let allowed_VIF_devices_PV = vif_inclusive_range 0 6


let allowed_VBD_devices_PV = range_inclusive 0 256 (** [possible_VBD_devices_of_string s] returns a list of Device_number.t which
represent possible interpretations of [s]. *)
let possible_VBD_devices_of_string s =
(* NB userdevice fields are arbitrary strings and device fields may be "" *)
let parse hvm x = try Some (Device_number.of_string hvm x) with _ -> None in
Listext.List.unbox_list [ parse true s; parse false s ]


let allowed_VIF_devices_HVM = range_inclusive 0 3 (** [all_used_VBD_devices __context self] returns a list of Device_number.t
which are considered to be already in-use in the VM *)
let all_used_VBD_devices ~__context ~self =
let all = Db.VM.get_VBDs ~__context ~self in


let allowed_VIF_devices_HVM_PP = range_inclusive 0 6 let existing_devices =
let all_devices = List.map (fun self -> Db.VBD.get_device ~__context ~self) all in
let all_devices2 = List.map (fun self -> Db.VBD.get_userdevice ~__context ~self) all in
all_devices @ all_devices2 in


let allowed_VIF_devices_PV = range_inclusive 0 6 List.concat (List.map possible_VBD_devices_of_string existing_devices)

(* If a user has requested a userdevice be set to 'autodetect' and it isn't currently
attached, then ignore it. If a userdevice is set to 'autodetect' then we assume the
device field contains the actual device in use. *)

(** Given a VBD returns either Some devicename or None in the case where a device is set to
autodetect and it hasn't been plugged in. *)
let get_device_name_in_use ~__context ~self =
try
let vbd_r = Db.VBD.get_record ~__context ~self in
match vbd_r.API.vBD_userdevice with
| "autodetect" -> Some vbd_r.API.vBD_device
| x -> Some x
with _ -> (* someone just destroyed the VBD *)
None

exception Invalid_device of string
let translate_vbd_device_to_number name =
try
let number =
match String.explode name with
| 's' :: 'd' :: ('a'..'p' as n) :: rest -> (int_of_char n) - (int_of_char 'a')
| 'x' :: 'v' :: 'd' :: ('a'..'p' as n) :: rest -> (int_of_char n) - (int_of_char 'a')
| 'h' :: 'd' :: ('a'..'p' as n) :: rest -> (int_of_char n) - (int_of_char 'a')
| _ -> int_of_string name
in
string_of_int number
with _ -> raise (Invalid_device name)


let allowed_VBD_devices ~__context ~vm = let allowed_VBD_devices ~__context ~vm =
let is_hvm = Helpers.will_boot_hvm ~__context ~self:vm in let is_hvm = Helpers.will_boot_hvm ~__context ~self:vm in
let guest_metrics = Db.VM.get_guest_metrics ~__context ~self:vm in let is_control_domain = Db.VM.get_is_control_domain ~__context ~self:vm in
let is_pp = let is_pp =
try try
(Db.VM_guest_metrics.get_PV_drivers_version ~__context ~self:guest_metrics) <> [] let guest_metrics = Db.VM.get_guest_metrics ~__context ~self:vm in
with (Db.VM_guest_metrics.get_PV_drivers_version ~__context ~self:guest_metrics) <> []
_ -> false with _ -> false in
in let all_devices = match is_hvm,is_pp,is_control_domain with
let all_devices = | false, _, true -> allowed_VBD_devices_control_domain
match is_hvm,is_pp with | false, _, false -> allowed_VBD_devices_PV
false,_ -> allowed_VBD_devices_PV | true, false, _ -> allowed_VBD_devices_HVM
| true,false -> allowed_VBD_devices_HVM | true, true, _ -> allowed_VBD_devices_HVM_PP
| true,true -> allowed_VBD_devices_HVM_PP in
in (* Filter out those we've already got VBDs for *)
(* Filter out those we've already got VBDs for *) let used_devices = all_used_VBD_devices ~__context ~self:vm in
let all_vbds = Db.VM.get_VBDs ~__context ~self:vm in List.filter (fun dev -> not (List.mem dev used_devices)) all_devices
let used_devices = List.map (fun self -> get_device_name_in_use ~__context ~self) all_vbds in
(* Remove all the Nones *)
let used_devices = List.concat (List.map Opt.to_list used_devices) in
let used_devices = List.map (fun name -> try translate_vbd_device_to_number name with _ -> name) used_devices in
List.filter (fun dev -> not (List.mem dev used_devices)) all_devices


let allowed_VIF_devices ~__context ~vm = let allowed_VIF_devices ~__context ~vm =
let is_hvm = Helpers.will_boot_hvm ~__context ~self:vm in let is_hvm = Helpers.will_boot_hvm ~__context ~self:vm in
Expand Down

0 comments on commit 1a8307d

Please sign in to comment.