@@ -458,6 +458,8 @@ module Storage = struct
458458
459459 let dp_destroy = dp_destroy
460460
461+ let detach = detach
462+
461463 let get_disk_by_name = get_disk_by_name
462464end
463465
@@ -3659,6 +3661,8 @@ module VBD = struct
36593661 let vm = fst vbd.id in
36603662 Storage. activate ~xc ~xs task vm dp sr vdi
36613663
3664+ (* TODO could split out a _deactivate function here *)
3665+
36623666 let frontend_domid_of_device device =
36633667 device.Device_common. frontend.Device_common. domid
36643668
@@ -4227,6 +4231,175 @@ module VBD = struct
42274231 raise (Xenopsd_error (Device_detach_rejected (" VBD" , id_of vbd, s)))
42284232 )
42294233
4234+ (* CP-53555: The deactivate half of VBD.unplug to allow them to be done separately *)
4235+ let deactivate task vm vbd force =
4236+ with_tracing ~task ~name: " VBD_deactivate" @@ fun () ->
4237+ with_xc_and_xs (fun xc xs ->
4238+ try
4239+ (* On destroying the datapath
4240+
4241+ 1. if the device has already been shutdown and deactivated (as in
4242+ suspend) we must call DP.destroy here to avoid leaks
4243+
4244+ 2. if the device is successfully shutdown here then we must call
4245+ DP.destroy because no-one else will
4246+
4247+ 3. if the device shutdown is rejected then we should leave the DP
4248+ alone and rely on the event thread calling us again later. *)
4249+ let domid = domid_of_uuid ~xs (uuid_of_string vm) in
4250+ (* If the device is gone then we don't need to shut it down but we do
4251+ need to free any storage resources. *)
4252+ let dev =
4253+ try
4254+ Some (device_by_id xc xs vm (device_kind_of ~xs vbd) (id_of vbd))
4255+ with
4256+ | Xenopsd_error (Does_not_exist (_ , _ )) ->
4257+ debug " VM = %s; VBD = %s; Ignoring missing domain" vm (id_of vbd) ;
4258+ None
4259+ | Xenopsd_error Device_not_connected ->
4260+ debug " VM = %s; VBD = %s; Ignoring missing device" vm (id_of vbd) ;
4261+ None
4262+ in
4263+ let backend =
4264+ match dev with
4265+ | None ->
4266+ None
4267+ | Some dv -> (
4268+ match
4269+ Rpcmarshal. unmarshal typ_of_backend
4270+ (Device.Generic. get_private_key ~xs dv _vdi_id
4271+ |> Jsonrpc. of_string
4272+ )
4273+ with
4274+ | Ok x ->
4275+ x
4276+ | Error (`Msg m ) ->
4277+ internal_error " Failed to unmarshal VBD backend: %s" m
4278+ )
4279+ in
4280+ Option. iter
4281+ (fun dev ->
4282+ if force && not (Device. can_surprise_remove ~xs dev) then
4283+ debug
4284+ " VM = %s; VBD = %s; Device is not surprise-removable \
4285+ (ignoring and removing anyway)"
4286+ vm (id_of vbd) ;
4287+ (* this happens on normal shutdown too *)
4288+ (* Case (1): success; Case (2): success; Case (3): an exception is
4289+ thrown *)
4290+ with_tracing ~task ~name: " VBD_deactivate_clean_shutdown"
4291+ @@ fun () ->
4292+ Xenops_task. with_subtask task
4293+ (Printf. sprintf " Vbd.clean_shutdown %s" (id_of vbd))
4294+ (fun () ->
4295+ (if force then Device. hard_shutdown else Device. clean_shutdown)
4296+ task ~xs dev
4297+ )
4298+ )
4299+ dev ;
4300+ (* We now have a shutdown device but an active DP: we should destroy
4301+ the DP if the backend is of type VDI *)
4302+ finally
4303+ (fun () ->
4304+ ( with_tracing ~task ~name: " VBD_deactivate_release" @@ fun () ->
4305+ Option. iter
4306+ (fun dev ->
4307+ Xenops_task. with_subtask task
4308+ (Printf. sprintf " Vbd.release %s" (id_of vbd))
4309+ (fun () -> Device.Vbd. release task ~xc ~xs dev)
4310+ )
4311+ dev
4312+ ) ;
4313+ (* If we have a qemu frontend, detach this too. *)
4314+ with_tracing ~task ~name: " VBD_deactivate_detach_qemu" @@ fun () ->
4315+ let _ =
4316+ DB. update vm
4317+ (Option. map (fun vm_t ->
4318+ let persistent = vm_t.VmExtra. persistent in
4319+ if List. mem_assoc vbd.Vbd. id persistent.VmExtra. qemu_vbds
4320+ then (
4321+ let _, qemu_vbd =
4322+ List. assoc vbd.Vbd. id persistent.VmExtra. qemu_vbds
4323+ in
4324+ (* destroy_vbd_frontend ignores 'refusing to close'
4325+ transients' *)
4326+ destroy_vbd_frontend ~xc ~xs task qemu_vbd ;
4327+ VmExtra.
4328+ {
4329+ persistent=
4330+ {
4331+ persistent with
4332+ qemu_vbds=
4333+ List. remove_assoc vbd.Vbd. id
4334+ persistent.qemu_vbds
4335+ }
4336+ }
4337+ ) else
4338+ vm_t
4339+ )
4340+ )
4341+ in
4342+ ()
4343+ )
4344+ (fun () ->
4345+ with_tracing ~task ~name: " VBD_deactivate_deactivate" @@ fun () ->
4346+ let vmid = Storage. vm_of_domid domid in
4347+ match (domid, backend) with
4348+ | Some x , Some (VDI path ) ->
4349+ let sr, vdi = Storage. get_disk_by_name task path in
4350+ let dp = Storage. id_of (string_of_int x) vbd.id in
4351+ Storage. deactivate task dp sr vdi vmid
4352+ (* TODO Do we only need to deactivate VDIs, not Local or CD? *)
4353+ | _ ->
4354+ ()
4355+ )
4356+ with Device_common. Device_error (_ , s ) ->
4357+ debug " Caught Device_error: %s" s ;
4358+ raise (Xenopsd_error (Device_detach_rejected (" VBD" , id_of vbd, s)))
4359+ )
4360+
4361+ (* CP-53555: The detach half of VBD.unplug to allow them to be done separately *)
4362+ let detach task vm vbd =
4363+ with_tracing ~task ~name: " VBD_detach" @@ fun () ->
4364+ with_xc_and_xs (fun xc xs ->
4365+ let domid = domid_of_uuid ~xs (uuid_of_string vm) in
4366+ let dev =
4367+ try
4368+ Some (device_by_id xc xs vm (device_kind_of ~xs vbd) (id_of vbd))
4369+ with
4370+ | Xenopsd_error (Does_not_exist (_ , _ )) ->
4371+ debug " VM = %s; VBD = %s; Ignoring missing domain" vm (id_of vbd) ;
4372+ None
4373+ | Xenopsd_error Device_not_connected ->
4374+ debug " VM = %s; VBD = %s; Ignoring missing device" vm (id_of vbd) ;
4375+ None
4376+ in
4377+ let backend =
4378+ match dev with
4379+ | None ->
4380+ None
4381+ | Some dv -> (
4382+ match
4383+ Rpcmarshal. unmarshal typ_of_backend
4384+ (Device.Generic. get_private_key ~xs dv _vdi_id
4385+ |> Jsonrpc. of_string
4386+ )
4387+ with
4388+ | Ok x ->
4389+ x
4390+ | Error (`Msg m ) ->
4391+ internal_error " Failed to unmarshal VBD backend: %s" m
4392+ )
4393+ in
4394+ with_tracing ~task ~name: " VBD_detach_dp_destroy" @@ fun () ->
4395+ match (domid, backend) with
4396+ | Some x , None | Some x , Some (VDI _ ) ->
4397+ Storage. detach task (Storage. id_of (string_of_int x) vbd.Vbd. id)
4398+ | _ ->
4399+ ()
4400+ ) ;
4401+ cleanup_attached_vdis vm vbd.id
4402+
42304403 let insert task vm vbd d =
42314404 on_frontend
42324405 (fun xc xs frontend_domid domain_type ->
0 commit comments