From 6f9f1e402220dee909a8195d6d29385d15ac589d Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Fri, 31 Oct 2025 11:23:32 +0100 Subject: [PATCH 1/2] vdi: enable resize_online command Signed-off-by: Anthoine Bourgeois --- ocaml/idl/datamodel.ml | 11 +------ ocaml/tests/test_vdi_allowed_operations.ml | 2 +- ocaml/xapi-idl/storage/storage_interface.ml | 14 +++++++++ ocaml/xapi-idl/storage/storage_skeleton.ml | 3 ++ ocaml/xapi-storage-script/main.ml | 15 ++++++++++ ocaml/xapi-storage/generator/lib/control.ml | 11 +++++++ .../generator/test/storage_test.ml | 1 + ocaml/xapi/message_forwarding.ml | 10 +++++++ ocaml/xapi/sm.ml | 14 +++++++++ ocaml/xapi/storage_mux.ml | 9 ++++++ ocaml/xapi/storage_smapiv1.ml | 25 ++++++++++++++++ ocaml/xapi/storage_smapiv1_wrapper.ml | 9 ++++++ ocaml/xapi/xapi_sr_operations.ml | 3 ++ ocaml/xapi/xapi_vdi.ml | 30 +++++++++++++++++-- ocaml/xapi/xapi_vdi.mli | 1 + 15 files changed, 144 insertions(+), 14 deletions(-) diff --git a/ocaml/idl/datamodel.ml b/ocaml/idl/datamodel.ml index bfe326e4356..f9f5410fd20 100644 --- a/ocaml/idl/datamodel.ml +++ b/ocaml/idl/datamodel.ml @@ -5336,16 +5336,7 @@ module VDI = struct ~doc:"Resize the VDI." ~allowed_roles:_R_VM_ADMIN () let resize_online = - call ~name:"resize_online" ~in_oss_since:None - ~lifecycle: - [ - (Published, rel_rio, "") - ; (Deprecated, rel_inverness, "Dummy transition") - ; ( Removed - , rel_inverness - , "Online VDI resize is not supported by any of the storage backends." - ) - ] + call ~name:"resize_online" ~in_oss_since:None ~lifecycle:[] ~params: [ (Ref _vdi, "vdi", "The VDI to resize") diff --git a/ocaml/tests/test_vdi_allowed_operations.ml b/ocaml/tests/test_vdi_allowed_operations.ml index 877b4fa48e5..5b1b1734409 100644 --- a/ocaml/tests/test_vdi_allowed_operations.ml +++ b/ocaml/tests/test_vdi_allowed_operations.ml @@ -549,7 +549,7 @@ let test_update_allowed_operations () = let allowed_operations = Db.VDI.get_allowed_operations ~__context ~self:vdi_ref in - let ok_ops : API.vdi_operations_set = [`snapshot; `clone; `copy] in + let ok_ops : API.vdi_operations_set = [`snapshot; `clone; `copy; `resize_online] in Alcotest.(check Alcotest_comparators.vdi_operations_set) "update_allowed_operations should be correct" ok_ops allowed_operations ; let vbd_ref = Db.VDI.get_VBDs ~__context ~self:vdi_ref |> List.hd in diff --git a/ocaml/xapi-idl/storage/storage_interface.ml b/ocaml/xapi-idl/storage/storage_interface.ml index eaabacc9e8f..d5d3d7f2771 100644 --- a/ocaml/xapi-idl/storage/storage_interface.ml +++ b/ocaml/xapi-idl/storage/storage_interface.ml @@ -813,6 +813,14 @@ module StorageAPI (R : RPC) = struct declare "VDI.resize" [] (dbg_p @-> sr_p @-> vdi_p @-> new_size_p @-> returning new_size_p err) + (** [resize_online task sr vdi new_size] makes a VDI's virtual_size at least + [new_size] bytes. The function returns the new virtual_size which may be + bigger (but not less than) requested. *) + let resize_online = + let new_size_p = Param.mk ~name:"new_size" Types.int64 in + declare "VDI.resize_online" [] + (dbg_p @-> sr_p @-> vdi_p @-> new_size_p @-> returning new_size_p err) + (** [destroy task sr vdi] removes [vdi] from [sr] *) let destroy = declare "VDI.destroy" [] @@ -1525,6 +1533,9 @@ module type Server_impl = sig val resize : context -> dbg:debug_info -> sr:sr -> vdi:vdi -> new_size:int64 -> int64 + val resize_online : + context -> dbg:debug_info -> sr:sr -> vdi:vdi -> new_size:int64 -> int64 + val destroy : context -> dbg:debug_info -> sr:sr -> vdi:vdi -> unit val stat : context -> dbg:debug_info -> sr:sr -> vdi:vdi -> vdi_info @@ -1780,6 +1791,9 @@ module Server (Impl : Server_impl) () = struct S.VDI.resize (fun dbg sr vdi new_size -> Impl.VDI.resize () ~dbg ~sr ~vdi ~new_size ) ; + S.VDI.resize_online (fun dbg sr vdi new_size -> + Impl.VDI.resize_online () ~dbg ~sr ~vdi ~new_size + ) ; S.VDI.destroy (fun dbg sr vdi -> Impl.VDI.destroy () ~dbg ~sr ~vdi) ; S.VDI.stat (fun dbg sr vdi -> Impl.VDI.stat () ~dbg ~sr ~vdi) ; S.VDI.introduce (fun dbg sr uuid sm_config location -> diff --git a/ocaml/xapi-idl/storage/storage_skeleton.ml b/ocaml/xapi-idl/storage/storage_skeleton.ml index a2d2d04ab08..a70b6daa548 100644 --- a/ocaml/xapi-idl/storage/storage_skeleton.ml +++ b/ocaml/xapi-idl/storage/storage_skeleton.ml @@ -106,6 +106,9 @@ module VDI = struct let resize ctx ~dbg ~sr ~vdi ~new_size = Storage_interface.unimplemented __FUNCTION__ + let resize_online ctx ~dbg ~sr ~vdi ~new_size = + Storage_interface.unimplemented __FUNCTION__ + let destroy ctx ~dbg ~sr ~vdi = Storage_interface.unimplemented __FUNCTION__ let stat ctx ~dbg ~sr ~vdi = Storage_interface.unimplemented __FUNCTION__ diff --git a/ocaml/xapi-storage-script/main.ml b/ocaml/xapi-storage-script/main.ml index 1eccd3867fd..c0b8f2890c8 100644 --- a/ocaml/xapi-storage-script/main.ml +++ b/ocaml/xapi-storage-script/main.ml @@ -898,6 +898,7 @@ module QueryImpl (M : META) = struct ; ("Volume.clone", "VDI_CLONE") ; ("Volume.snapshot", "VDI_SNAPSHOT") ; ("Volume.resize", "VDI_RESIZE") + ; ("Volume.resize_online", "VDI_RESIZE_ONLINE") ; ("Volume.destroy", "VDI_DELETE") ; ("Volume.stat", "VDI_UPDATE") ] @@ -1504,6 +1505,19 @@ module VDIImpl (M : META) = struct ) |> wrap + let vdi_resize_online_impl dbg sr vdi' new_size = + (let vdi = Storage_interface.Vdi.string_of vdi' in + Attached_SRs.find sr >>>= fun sr -> + return_volume_rpc (fun () -> + Volume_client.resize_online (volume_rpc ~dbg) dbg sr vdi new_size + ) + >>>= fun () -> + (* Now call Volume.stat to discover the size *) + stat ~dbg ~sr ~vdi >>>= fun response -> + return response.Xapi_storage.Control.virtual_size + ) + |> wrap + let vdi_stat_impl dbg sr vdi' = (let vdi = Storage_interface.Vdi.string_of vdi' in Attached_SRs.find sr >>>= fun sr -> @@ -1934,6 +1948,7 @@ let bind ~volume_script_dir = S.VDI.set_name_label VDI.vdi_set_name_label_impl ; S.VDI.set_name_description VDI.vdi_set_name_description_impl ; S.VDI.resize VDI.vdi_resize_impl ; + S.VDI.resize_online VDI.vdi_resize_online_impl ; S.VDI.stat VDI.vdi_stat_impl ; S.VDI.introduce VDI.vdi_introduce_impl ; S.VDI.attach3 VDI.vdi_attach3_impl ; diff --git a/ocaml/xapi-storage/generator/lib/control.ml b/ocaml/xapi-storage/generator/lib/control.ml index e7f9274c48a..4749a97923e 100644 --- a/ocaml/xapi-storage/generator/lib/control.ml +++ b/ocaml/xapi-storage/generator/lib/control.ml @@ -330,6 +330,17 @@ module Volume (R : RPC) = struct ] (dbg @-> sr @-> key @-> new_size @-> returning unit errors) + let resize_online = + let new_size = + Param.mk ~name:"new_size" ~description:["New disk size"] Types.int64 + in + R.declare "resize_online" + [ + "[resize_online sr volume new_size] enlarges [volume] to be at least " + ; "[new_size]." + ] + (dbg @-> sr @-> key @-> new_size @-> returning unit errors) + let stat = R.declare "stat" ["[stat sr volume] returns metadata associated with [volume]."] diff --git a/ocaml/xapi-storage/generator/test/storage_test.ml b/ocaml/xapi-storage/generator/test/storage_test.ml index 3da8be64711..25886663903 100644 --- a/ocaml/xapi-storage/generator/test/storage_test.ml +++ b/ocaml/xapi-storage/generator/test/storage_test.ml @@ -181,6 +181,7 @@ let volume_server () = Volume.set unimplemented ; Volume.unset unimplemented ; Volume.resize unimplemented ; + Volume.resize_online unimplemented ; Volume.stat unimplemented ; Volume.compare unimplemented ; Volume.similar_content unimplemented ; diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index af2b1aa1458..199943a86e2 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -5443,6 +5443,16 @@ functor forward_vdi_op ~local_fn ~__context ~self:vdi ~remote_fn ) + let resize_online ~__context ~vdi ~size = + info "VDI.resize_online: VDI = '%s'; size = %Ld" (vdi_uuid ~__context vdi) size ; + let local_fn = Local.VDI.resize_online ~vdi ~size in + let remote_fn = Client.VDI.resize_online ~vdi ~size in + let sR = Db.VDI.get_SR ~__context ~self:vdi in + with_sr_andor_vdi ~__context ~sr:(sR, `vdi_resize) ~vdi:(vdi, `resize_online) + ~doc:"VDI.resize_online" (fun () -> + forward_vdi_op ~local_fn ~__context ~self:vdi ~remote_fn + ) + let generate_config ~__context ~host ~vdi = info "VDI.generate_config: VDI = '%s'; host = '%s'" (vdi_uuid ~__context vdi) diff --git a/ocaml/xapi/sm.ml b/ocaml/xapi/sm.ml index 1d198cf3f98..10ff63ee73e 100644 --- a/ocaml/xapi/sm.ml +++ b/ocaml/xapi/sm.ml @@ -299,6 +299,20 @@ let vdi_resize ~dbg dconf driver sr vdi newsize = in Sm_exec.parse_vdi_info (Sm_exec.exec_xmlrpc ~dbg (driver_filename driver) call) +let vdi_resize_online ~dbg dconf driver sr vdi newsize = + with_dbg ~dbg ~name:"vdi_resize_online" @@ fun di -> + let dbg = Debug_info.to_string di in + debug "vdi_resize_online" driver + (sprintf "sr=%s vdi=%s newsize=%Ld" (Ref.string_of sr) (Ref.string_of vdi) + newsize + ) ; + srmaster_only dconf ; + let call = + Sm_exec.make_call ~sr_ref:sr ~vdi_ref:vdi dconf "vdi_resize_online" + [sprintf "%Lu" newsize] + in + Sm_exec.parse_vdi_info (Sm_exec.exec_xmlrpc ~dbg (driver_filename driver) call) + let vdi_generate_config ~dbg dconf driver sr vdi = with_dbg ~dbg ~name:"vdi_generate_config" @@ fun di -> let dbg = Debug_info.to_string di in diff --git a/ocaml/xapi/storage_mux.ml b/ocaml/xapi/storage_mux.ml index 0427f76ca54..f6e6570f3d4 100644 --- a/ocaml/xapi/storage_mux.ml +++ b/ocaml/xapi/storage_mux.ml @@ -480,6 +480,15 @@ module Mux = struct end)) in C.VDI.resize (Debug_info.to_string di) sr vdi new_size + let resize_online () ~dbg ~sr ~vdi ~new_size = + with_dbg ~name:"VDI.resize_online" ~dbg @@ fun di -> + info "VDI.resize_online dbg:%s sr:%s vdi:%s new_size:%Ld" dbg (s_of_sr sr) + (s_of_vdi vdi) new_size ; + let module C = StorageAPI (Idl.Exn.GenClient (struct + let rpc = of_sr sr + end)) in + C.VDI.resize_online (Debug_info.to_string di) sr vdi new_size + let destroy () ~dbg ~sr ~vdi = with_dbg ~name:"VDI.destroy" ~dbg @@ fun di -> info "VDI.destroy dbg:%s sr:%s vdi:%s" dbg (s_of_sr sr) (s_of_vdi vdi) ; diff --git a/ocaml/xapi/storage_smapiv1.ml b/ocaml/xapi/storage_smapiv1.ml index 0995edc35c4..b2f46efa027 100644 --- a/ocaml/xapi/storage_smapiv1.ml +++ b/ocaml/xapi/storage_smapiv1.ml @@ -771,6 +771,31 @@ module SMAPIv1 : Server_impl = struct | Sm.MasterOnly -> redirect sr + let resize_online _context ~dbg ~sr ~vdi ~new_size = + with_dbg ~name:"VDI.resize_online" ~dbg @@ fun di -> + let dbg = Debug_info.to_string di in + try + let vi = + for_vdi ~dbg ~sr ~vdi "VDI.resize_online" (fun device_config _type sr self -> + Sm.vdi_resize_online ~dbg device_config _type sr self new_size + ) + in + Server_helpers.exec_with_new_task "VDI.resize_online" + ~subtask_of:(Ref.of_string dbg) (fun __context -> + let self, _ = + find_vdi ~__context sr + (Storage_interface.Vdi.of_string vi.Smint.vdi_info_location) + in + Db.VDI.get_virtual_size ~__context ~self + ) + with + | Api_errors.Server_error (code, params) -> + raise (Storage_error (Backend_error (code, params))) + | Smint.Not_implemented_in_backend -> + raise (Storage_error (Unimplemented "VDI.resize_online")) + | Sm.MasterOnly -> + redirect sr + let destroy _context ~dbg ~sr ~vdi = with_dbg ~name:"VDI.destroy" ~dbg @@ fun di -> let dbg = Debug_info.to_string di in diff --git a/ocaml/xapi/storage_smapiv1_wrapper.ml b/ocaml/xapi/storage_smapiv1_wrapper.ml index 86879780fba..085b3ba3b5b 100644 --- a/ocaml/xapi/storage_smapiv1_wrapper.ml +++ b/ocaml/xapi/storage_smapiv1_wrapper.ml @@ -814,6 +814,15 @@ functor Impl.VDI.resize context ~dbg ~sr ~vdi ~new_size ) + let resize_online context ~dbg ~sr ~vdi ~new_size = + with_dbg ~name:"VDI.resize_online" ~dbg @@ fun di -> + info "VDI.resize_online dbg:%s sr:%s vdi:%s new_size:%Ld" di.log (s_of_sr sr) + (s_of_vdi vdi) new_size ; + let dbg = Debug_info.to_string di in + with_vdi sr vdi (fun () -> + Impl.VDI.resize_online context ~dbg ~sr ~vdi ~new_size + ) + let destroy_and_data_destroy call_name call_f context ~dbg ~sr ~vdi = with_dbg ~name:call_name ~dbg @@ fun di -> info "%s dbg:%s sr:%s vdi:%s" call_name di.log (s_of_sr sr) diff --git a/ocaml/xapi/xapi_sr_operations.ml b/ocaml/xapi/xapi_sr_operations.ml index b08a82c20f2..ac9b7beedd8 100644 --- a/ocaml/xapi/xapi_sr_operations.ml +++ b/ocaml/xapi/xapi_sr_operations.ml @@ -39,6 +39,7 @@ let all_ops : API.storage_operations_set = ; `vdi_create ; `vdi_destroy ; `vdi_resize + ; `vdi_resize_online ; `vdi_clone ; `vdi_snapshot ; `vdi_mirror @@ -64,6 +65,7 @@ let all_rpu_ops : API.storage_operations_set = ; `vdi_create ; `vdi_destroy ; `vdi_resize + ; `vdi_resize_online ; `vdi_clone ; `vdi_snapshot ; `vdi_introduce @@ -81,6 +83,7 @@ let sm_cap_table : (API.storage_operations * _) list = (`vdi_create, Vdi_create) ; (`vdi_destroy, Vdi_delete) ; (`vdi_resize, Vdi_resize) + ; (`vdi_resize_online, Vdi_resize) ; (`vdi_introduce, Vdi_introduce) ; (`vdi_mirror, Vdi_mirror) ; (`vdi_enable_cbt, Vdi_configure_cbt) diff --git a/ocaml/xapi/xapi_vdi.ml b/ocaml/xapi/xapi_vdi.ml index 1148efe09c5..6d73f69d80c 100644 --- a/ocaml/xapi/xapi_vdi.ml +++ b/ocaml/xapi/xapi_vdi.ml @@ -31,12 +31,10 @@ let feature_of_op = Some Vdi_snapshot | `destroy -> Some Vdi_delete - | `resize -> + | `resize | `resize_online -> Some Vdi_resize | `update -> Some Vdi_update - | `resize_online -> - Some Vdi_resize_online | `generate_config -> Some Vdi_generate_config | `clone -> @@ -407,6 +405,12 @@ let check_operation_error ~__context ?sr_records:_ ?(pbd_records = []) | `resize_online -> if ha_enabled && vdi_is_ha_state_or_redolog then Error (Api_errors.ha_is_enabled, []) + else if my_active_vbd_records = [] then + Error ( Api_errors.operation_not_allowed + , [ + "VDI is not attached to a running VM, online operation is not allowed." + ] + ) else Ok () | `snapshot when record.Db_actions.vDI_sharable -> @@ -1081,6 +1085,26 @@ let resize ~__context ~vdi ~size = Db.VDI.set_virtual_size ~__context ~self:vdi ~value:new_size ) +let resize_online ~__context ~vdi ~size = + Sm.assert_pbd_is_plugged ~__context ~sr:(Db.VDI.get_SR ~__context ~self:vdi) ; + Xapi_vdi_helpers.assert_managed ~__context ~vdi ; + Storage_utils.transform_storage_exn (fun () -> + let module C = Storage_interface.StorageAPI (Idl.Exn.GenClient (struct + let rpc = Storage_access.rpc + end)) in + let sr = Db.VDI.get_SR ~__context ~self:vdi in + let sr = + Db.SR.get_uuid ~__context ~self:sr |> Storage_interface.Sr.of_string + in + let vdi' = + Db.VDI.get_location ~__context ~self:vdi + |> Storage_interface.Vdi.of_string + in + let dbg = Ref.string_of (Context.get_task_id __context) in + let new_size = C.VDI.resize_online dbg sr vdi' size in + Db.VDI.set_virtual_size ~__context ~self:vdi ~value:new_size + ) + let generate_config ~__context ~host:_ ~vdi = Sm.assert_pbd_is_plugged ~__context ~sr:(Db.VDI.get_SR ~__context ~self:vdi) ; Xapi_vdi_helpers.assert_managed ~__context ~vdi ; diff --git a/ocaml/xapi/xapi_vdi.mli b/ocaml/xapi/xapi_vdi.mli index 3d60ad31ff1..2abe2e6f3cc 100644 --- a/ocaml/xapi/xapi_vdi.mli +++ b/ocaml/xapi/xapi_vdi.mli @@ -163,6 +163,7 @@ val _data_destroy : unit tests. *) val resize : __context:Context.t -> vdi:[`VDI] API.Ref.t -> size:int64 -> unit +val resize_online : __context:Context.t -> vdi:[`VDI] API.Ref.t -> size:int64 -> unit val generate_config : __context:Context.t -> host:'a -> vdi:[`VDI] API.Ref.t -> string From ad7629726d6bec26db5b5b2a33138e778a36f1c5 Mon Sep 17 00:00:00 2001 From: Anthoine Bourgeois Date: Thu, 6 Nov 2025 15:26:41 +0100 Subject: [PATCH 2/2] xenopsd: trigger online resize by writing xenstore Signed-off-by: Anthoine Bourgeois --- ocaml/idl/datamodel.ml | 13 ++++++++++++ ocaml/idl/schematest.ml | 2 +- ocaml/xapi-cli-server/cli_operations.ml | 22 +++++++++++++++++--- ocaml/xapi-idl/xen/xenops_interface.ml | 5 +++++ ocaml/xapi/message_forwarding.ml | 9 ++++++++ ocaml/xapi/xapi_vbd.ml | 4 ++++ ocaml/xapi/xapi_vbd_helpers.ml | 2 +- ocaml/xapi/xapi_xenops.ml | 16 ++++++++++++++ ocaml/xenopsd/lib/xenops_server.ml | 19 +++++++++++++++++ ocaml/xenopsd/lib/xenops_server_plugin.ml | 2 ++ ocaml/xenopsd/lib/xenops_server_simulator.ml | 2 ++ ocaml/xenopsd/lib/xenops_server_skeleton.ml | 2 ++ ocaml/xenopsd/xc/xenops_server_xen.ml | 18 ++++++++++++++++ 13 files changed, 111 insertions(+), 5 deletions(-) diff --git a/ocaml/idl/datamodel.ml b/ocaml/idl/datamodel.ml index f9f5410fd20..6e01d461f05 100644 --- a/ocaml/idl/datamodel.ml +++ b/ocaml/idl/datamodel.ml @@ -6504,6 +6504,7 @@ module VBD = struct ; ("unplug_force", "Attempting to forcibly unplug this VBD") ; ("pause", "Attempting to pause a block device backend") ; ("unpause", "Attempting to unpause a block device backend") + ; ("resize_online", "Attempting to online resize a block device backend") ] ) @@ -6533,6 +6534,17 @@ module VBD = struct ~errs:[Api_errors.vbd_not_removable_media; Api_errors.vbd_not_empty] ~allowed_roles:_R_VM_OP () + let resize_online = + call ~name:"resize_online" + ~lifecycle:[(Published, rel_rio, "Resize a media online")] + ~doc:"Resize a media online" + ~params: + [ + (Ref _vbd, "vbd", "The vbd representing the device") + ; (Int, "size", "The new size of the media") + ] + ~allowed_roles:_R_VM_ADMIN () + let plug = call ~name:"plug" ~lifecycle: @@ -6714,6 +6726,7 @@ module VBD = struct ; pause ; unpause ; set_mode + ; resize_online ] ~contents: ([ diff --git a/ocaml/idl/schematest.ml b/ocaml/idl/schematest.ml index 9411d1c3b42..9374dc5f3ed 100644 --- a/ocaml/idl/schematest.ml +++ b/ocaml/idl/schematest.ml @@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex (* BEWARE: if this changes, check that schema has been bumped accordingly in ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *) -let last_known_schema_hash = "3b20f4304cfaaa7b6213af91ae632e64" +let last_known_schema_hash = "acf96a87d6dad370c7000e7d299c1f41" let current_schema_hash : string = let open Datamodel_types in diff --git a/ocaml/xapi-cli-server/cli_operations.ml b/ocaml/xapi-cli-server/cli_operations.ml index eb6a0eb3a80..906ed260e3f 100644 --- a/ocaml/xapi-cli-server/cli_operations.ml +++ b/ocaml/xapi-cli-server/cli_operations.ml @@ -2008,9 +2008,25 @@ let vdi_resize _printer rpc session_id params = let online = List.mem_assoc "online" params && List.assoc "online" params = "true" in - if online then - Client.VDI.resize_online ~rpc ~session_id ~vdi ~size:new_size - else + if online then ( + Client.VDI.resize_online ~rpc ~session_id ~vdi ~size:new_size; + let all_vbds = Client.VDI.get_VBDs ~rpc ~session_id ~self:vdi in + let all_vbd_records = List.map (vbd_record rpc session_id) all_vbds in + let active_records = + List.filter + (fun x -> (field_lookup x.fields "currently-attached").get () = "true") + all_vbd_records + in + List.iter + (fun vbd_record -> + let vbd_uuid = (field_lookup vbd_record.fields "uuid").get () in + let vbd = + Client.VBD.get_by_uuid ~rpc ~session_id ~uuid:vbd_uuid + in + Client.VBD.resize_online ~rpc ~session_id ~vbd ~size:new_size + ) + active_records + ) else Client.VDI.resize ~rpc ~session_id ~vdi ~size:new_size let vdi_generate_config printer rpc session_id params = diff --git a/ocaml/xapi-idl/xen/xenops_interface.ml b/ocaml/xapi-idl/xen/xenops_interface.ml index a67c51b0131..23c85f41ef1 100644 --- a/ocaml/xapi-idl/xen/xenops_interface.ml +++ b/ocaml/xapi-idl/xen/xenops_interface.ml @@ -955,6 +955,11 @@ module XenopsAPI (R : RPC) = struct let remove = declare "VBD.remove" [] (debug_info_p @-> vbd_id_p @-> returning unit_p err) + + let resize_online = + let new_size_p = Param.mk ~name:"new_size" Types.int64 in + declare "VBD.resize_online" [] + (debug_info_p @-> vbd_id_p @-> new_size_p @-> returning task_id_p err) end module VUSB = struct diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index 199943a86e2..ae09f1a0ca6 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -5705,6 +5705,15 @@ functor let assert_attachable ~__context ~self = info "VBD.assert_attachable: VBD = '%s'" (vbd_uuid ~__context self) ; Local.VBD.assert_attachable ~__context ~self + + let resize_online ~__context ~vbd ~size = + info "VBD.resize_online: VBD = '%s'; size = %Ld" (vbd_uuid ~__context vbd) size ; + let local_fn = Local.VBD.resize_online ~vbd ~size in + let remote_fn = Client.VBD.resize_online ~vbd ~size in + with_vbd_marked ~__context ~vbd ~doc:"VBD.resize_online" ~op:`resize_online (fun () -> + forward_vbd_op ~local_fn ~__context ~self:vbd ~remote_fn + ) ; + update_vbd_and_vdi_operations ~__context ~vbd end module VBD_metrics = struct end diff --git a/ocaml/xapi/xapi_vbd.ml b/ocaml/xapi/xapi_vbd.ml index 331284eb344..cd54a9b74b9 100644 --- a/ocaml/xapi/xapi_vbd.ml +++ b/ocaml/xapi/xapi_vbd.ml @@ -342,6 +342,10 @@ let insert ~__context ~vbd ~vdi = assert_ok_to_insert ~__context ~vbd ~vdi ; Xapi_xenops.vbd_insert ~__context ~self:vbd ~vdi +let resize_online ~__context ~vbd ~size = + assert_not_empty ~__context ~vbd ; + Xapi_xenops.vbd_resize_online ~__context ~self:vbd ~value:size + let assert_ok_to_eject ~__context ~vbd = let vm = Db.VBD.get_VM ~__context ~self:vbd in assert_removable ~__context ~vbd ; diff --git a/ocaml/xapi/xapi_vbd_helpers.ml b/ocaml/xapi/xapi_vbd_helpers.ml index 07d6b012da2..64db369639f 100644 --- a/ocaml/xapi/xapi_vbd_helpers.ml +++ b/ocaml/xapi/xapi_vbd_helpers.ml @@ -29,7 +29,7 @@ open D open Record_util let all_ops : API.vbd_operations_set = - [`attach; `eject; `unplug; `unplug_force; `insert; `plug; `pause; `unpause] + [`attach; `eject; `unplug; `unplug_force; `insert; `plug; `pause; `unpause; `resize_online] type table = (API.vbd_operations, (string * string list) option) Hashtbl.t diff --git a/ocaml/xapi/xapi_xenops.ml b/ocaml/xapi/xapi_xenops.ml index 9b12bcec5a6..985f99c0626 100644 --- a/ocaml/xapi/xapi_xenops.ml +++ b/ocaml/xapi/xapi_xenops.ml @@ -4213,6 +4213,22 @@ let vbd_insert_hvm ~__context ~self ~vdi = (Ref.string_of self) (Ref.string_of vdi) (Ref.string_of vdi) ) +let vbd_resize_online ~__context ~self ~value = + let@ __context = Context.with_tracing ~__context __FUNCTION__ in + let vm = Db.VBD.get_VM ~__context ~self in + let queue_name = queue_of_vm ~__context ~self:vm in + transform_xenops_exn ~__context ~vm queue_name (fun () -> + assert_resident_on ~__context ~self:vm ; + let vbd = md_of_vbd ~__context ~self in + info "xenops: VBD.resize_online %s.%s %Ld" (fst vbd.Vbd.id) (snd vbd.Vbd.id) value ; + let id = id_of_vm ~__context ~self:vm in + let dbg = Context.string_of_task_and_tracing __context in + let module Client = (val make_client queue_name : XENOPS) in + debug "xenops: VBD.resize_online %s" id ; + Client.VBD.resize_online dbg vbd.Vbd.id value |> sync_with_task __context queue_name ; + Events_from_xenopsd.wait queue_name dbg id () + ) + let has_qemu ~__context ~vm = let@ __context = Context.with_tracing ~__context __FUNCTION__ in let dbg = Context.string_of_task_and_tracing __context in diff --git a/ocaml/xenopsd/lib/xenops_server.ml b/ocaml/xenopsd/lib/xenops_server.ml index 6a06b36ba14..3cf623897cd 100644 --- a/ocaml/xenopsd/lib/xenops_server.ml +++ b/ocaml/xenopsd/lib/xenops_server.ml @@ -134,6 +134,7 @@ type atomic = | VBD_detach of Vbd.id | VBD_insert of Vbd.id * disk | VBD_set_active of Vbd.id * bool + | VBD_resize_online of Vbd.id * int64 | VM_remove of Vm.id | PCI_plug of Pci.id * bool (* use Qmp.add_device *) | PCI_unplug of Pci.id @@ -223,6 +224,8 @@ let rec name_of_atomic = function "VBD_insert" | VBD_set_active _ -> "VBD_set_active" + | VBD_resize_online _ -> + "VBD_resize_online" | VM_remove _ -> "VM_remove" | PCI_plug _ -> @@ -2138,6 +2141,17 @@ let rec perform_atomic ~progress_callback ?result (op : atomic) | _ -> raise (Xenopsd_error (Bad_power_state (power, Running))) ) + | VBD_resize_online (id, new_size) -> ( + debug "VBD.resize_online %s" (VBD_DB.string_of_id id) ; + let vbd_t = VBD_DB.read_exn id in + let power = (B.VM.get_state (VM_DB.read_exn (fst id))).Vm.power_state in + match power with + | Running | Paused -> + B.VBD.resize_online t (VBD_DB.vm_of id) vbd_t new_size ; + VBD_DB.signal id + | _ -> + raise (Xenopsd_error (Bad_power_state (power, Running))) + ) | VM_remove id -> ( debug "VM.remove %s" id ; let vm_t = VM_DB.read_exn id in @@ -2624,6 +2638,7 @@ and trigger_cleanup_after_failure_atom op t = | VBD_unplug (id, _) | VBD_deactivate (id, _) | VBD_detach id + | VBD_resize_online (id, _) | VBD_insert (id, _) -> immediate_operation dbg (fst id) (VBD_check_state id) | VIF_plug id @@ -3555,6 +3570,9 @@ module VBD = struct Debug.with_thread_associated dbg (fun () -> debug "VBD.list %s" vm ; DB.list vm) () + + let resize_online _ dbg id new_size = + queue_operation dbg (DB.vm_of id) (Atomic (VBD_resize_online (id, new_size))) end module VIF = struct @@ -4421,6 +4439,7 @@ let _ = Server.VBD.unplug (VBD.unplug ()) ; Server.VBD.eject (VBD.eject ()) ; Server.VBD.insert (VBD.insert ()) ; + Server.VBD.resize_online (VBD.resize_online ()) ; Server.VUSB.add (VUSB.add ()) ; Server.VUSB.remove (VUSB.remove ()) ; Server.VUSB.stat (VUSB.stat ()) ; diff --git a/ocaml/xenopsd/lib/xenops_server_plugin.ml b/ocaml/xenopsd/lib/xenops_server_plugin.ml index e4a61bb9ac8..0de0d64213a 100644 --- a/ocaml/xenopsd/lib/xenops_server_plugin.ml +++ b/ocaml/xenopsd/lib/xenops_server_plugin.ml @@ -229,6 +229,8 @@ module type S = sig val get_device_action_request : Vm.id -> Vbd.t -> device_action_request option + + val resize_online : Xenops_task.task_handle -> Vm.id -> Vbd.t -> int64 -> unit end module VIF : sig diff --git a/ocaml/xenopsd/lib/xenops_server_simulator.ml b/ocaml/xenopsd/lib/xenops_server_simulator.ml index 0c6ac3f606b..dc4bab0d754 100644 --- a/ocaml/xenopsd/lib/xenops_server_simulator.ml +++ b/ocaml/xenopsd/lib/xenops_server_simulator.ml @@ -693,6 +693,8 @@ module VBD = struct let get_state vm vbd = with_lock m (vbd_state vm vbd) let get_device_action_request _vm _vbd = None + + let resize_online task vm vbd new_size = () end module VIF = struct diff --git a/ocaml/xenopsd/lib/xenops_server_skeleton.ml b/ocaml/xenopsd/lib/xenops_server_skeleton.ml index 1a42aafafb4..36a9d27e566 100644 --- a/ocaml/xenopsd/lib/xenops_server_skeleton.ml +++ b/ocaml/xenopsd/lib/xenops_server_skeleton.ml @@ -164,6 +164,8 @@ module VBD = struct let get_state _ _ = unplugged_vbd let get_device_action_request _ _ = None + + let resize_online _ _ _ _ = unimplemented __FUNCTION__ end module VIF = struct diff --git a/ocaml/xenopsd/xc/xenops_server_xen.ml b/ocaml/xenopsd/xc/xenops_server_xen.ml index 5274569ef4e..3e808082edc 100644 --- a/ocaml/xenopsd/xc/xenops_server_xen.ml +++ b/ocaml/xenopsd/xc/xenops_server_xen.ml @@ -4311,6 +4311,24 @@ module VBD = struct vm (id_of vbd) ; None ) + + let resize_online task vm vbd new_size = + with_xc_and_xs (fun xc xs -> + let (device : Device_common.device) = + device_by_id xc xs vm (device_kind_of ~xs vbd) (id_of vbd) + in + debug "VM = %s; VBD = %s; VBD.resize_online %s new_size %Ld" vm + (id_of vbd) + (Device_common.string_of_device device) + new_size ; + let backend_path = Device_common.backend_path_of_device ~xs device in + let sectors_path = backend_path ^ "/sectors" in + let resize_path = backend_path ^ "/resize-device" in + debug "xenstore-write %s = %Ld" sectors_path new_size; + xs.Xs.write sectors_path (Int64.to_string new_size); + debug "xenstore-write %s" resize_path; + xs.Xs.write resize_path "" + ) end module VIF = struct