@@ -3863,6 +3863,127 @@ module VBD = struct
38633863 )
38643864 (fun () -> cleanup_attached_vdis vm (id_of vbd))
38653865
3866+ let unplug task vm vbd force =
3867+ with_xc_and_xs (fun xc xs ->
3868+ try
3869+ (* On destroying the datapath
3870+
3871+ 1. if the device has already been shutdown and deactivated (as in
3872+ suspend) we must call DP.destroy here to avoid leaks
3873+
3874+ 2. if the device is successfully shutdown here then we must call
3875+ DP.destroy because no-one else will
3876+
3877+ 3. if the device shutdown is rejected then we should leave the DP
3878+ alone and rely on the event thread calling us again later. *)
3879+ let domid = domid_of_uuid ~xs (uuid_of_string vm) in
3880+ (* If the device is gone then we don't need to shut it down but we do
3881+ need to free any storage resources. *)
3882+ let dev =
3883+ try
3884+ Some (device_by_id xc xs vm (device_kind_of ~xs vbd) (id_of vbd))
3885+ with
3886+ | Xenopsd_error (Does_not_exist (_ , _ )) ->
3887+ debug " VM = %s; VBD = %s; Ignoring missing domain" vm (id_of vbd) ;
3888+ None
3889+ | Xenopsd_error Device_not_connected ->
3890+ debug " VM = %s; VBD = %s; Ignoring missing device" vm (id_of vbd) ;
3891+ None
3892+ in
3893+ let backend =
3894+ match dev with
3895+ | None ->
3896+ None
3897+ | Some dv -> (
3898+ match
3899+ Rpcmarshal. unmarshal typ_of_backend
3900+ (Device.Generic. get_private_key ~xs dv _vdi_id
3901+ |> Jsonrpc. of_string
3902+ )
3903+ with
3904+ | Ok x ->
3905+ x
3906+ | Error (`Msg m ) ->
3907+ internal_error " Failed to unmarshal VBD backend: %s" m
3908+ )
3909+ in
3910+ Option. iter
3911+ (fun dev ->
3912+ if force && not (Device. can_surprise_remove ~xs dev) then
3913+ debug
3914+ " VM = %s; VBD = %s; Device is not surprise-removable \
3915+ (ignoring and removing anyway)"
3916+ vm (id_of vbd) ;
3917+ (* this happens on normal shutdown too *)
3918+ (* Case (1): success; Case (2): success; Case (3): an exception is
3919+ thrown *)
3920+ with_tracing ~task ~name: " VBD_device_shutdown" @@ fun () ->
3921+ Xenops_task. with_subtask task
3922+ (Printf. sprintf " Vbd.clean_shutdown %s" (id_of vbd))
3923+ (fun () ->
3924+ (if force then Device. hard_shutdown else Device. clean_shutdown)
3925+ task ~xs dev
3926+ )
3927+ )
3928+ dev ;
3929+ (* We now have a shutdown device but an active DP: we should destroy
3930+ the DP if the backend is of type VDI *)
3931+ finally
3932+ (fun () ->
3933+ with_tracing ~task ~name: " VBD_device_release" (fun () ->
3934+ Option. iter
3935+ (fun dev ->
3936+ Xenops_task. with_subtask task
3937+ (Printf. sprintf " Vbd.release %s" (id_of vbd))
3938+ (fun () -> Device.Vbd. release task ~xc ~xs dev)
3939+ )
3940+ dev
3941+ ) ;
3942+ (* If we have a qemu frontend, detach this too. *)
3943+ with_tracing ~task ~name: " VBD_detach_qemu" @@ fun () ->
3944+ let _ =
3945+ DB. update vm
3946+ (Option. map (fun vm_t ->
3947+ let persistent = vm_t.VmExtra. persistent in
3948+ if List. mem_assoc vbd.Vbd. id persistent.VmExtra. qemu_vbds
3949+ then (
3950+ let _, qemu_vbd =
3951+ List. assoc vbd.Vbd. id persistent.VmExtra. qemu_vbds
3952+ in
3953+ (* destroy_vbd_frontend ignores 'refusing to close'
3954+ transients' *)
3955+ destroy_vbd_frontend ~xc ~xs task qemu_vbd ;
3956+ VmExtra.
3957+ {
3958+ persistent=
3959+ {
3960+ persistent with
3961+ qemu_vbds=
3962+ List. remove_assoc vbd.Vbd. id
3963+ persistent.qemu_vbds
3964+ }
3965+ }
3966+ ) else
3967+ vm_t
3968+ )
3969+ )
3970+ in
3971+ ()
3972+ )
3973+ (fun () ->
3974+ with_tracing ~task ~name: " VBD_dp_destroy" @@ fun () ->
3975+ match (domid, backend) with
3976+ | Some x , None | Some x , Some (VDI _ ) ->
3977+ Storage. dp_destroy task
3978+ (Storage. id_of (string_of_int x) vbd.Vbd. id)
3979+ | _ ->
3980+ ()
3981+ )
3982+ with Device_common. Device_error (_ , s ) ->
3983+ debug " Caught Device_error: %s" s ;
3984+ raise (Xenopsd_error (Device_detach_rejected (" VBD" , id_of vbd, s)))
3985+ )
3986+
38663987 let deactivate task vm vbd force =
38673988 with_xc_and_xs (fun xc xs ->
38683989 try
0 commit comments