@@ -36,6 +36,8 @@ let info fmt =
36
36
end
37
37
) fmt
38
38
39
+ let _nonpersistent = " NONPERSISTENT"
40
+
39
41
let backend_error name args =
40
42
let open Storage_interface in
41
43
let exnty = Exception. Backend_error (name, args) in
@@ -171,6 +173,11 @@ module Datapath_plugins = struct
171
173
let unregister root_dir name =
172
174
Hashtbl. remove ! table name;
173
175
return ()
176
+
177
+ let supports_feature scheme feature =
178
+ match Hashtbl. find ! table scheme with
179
+ | None -> false
180
+ | Some query_result -> List. mem query_result.Storage.Plugin.Types. features feature
174
181
end
175
182
176
183
let vdi_of_volume x =
@@ -191,23 +198,36 @@ let vdi_of_volume x =
191
198
persistent = true ;
192
199
}
193
200
194
- let choose_datapath = function
195
- | [] -> return (Error (missing_uri () ))
196
- | uri :: _ ->
197
- let uri' = Uri. of_string uri in
198
- let domain = " 0" in
199
- begin match Uri. scheme uri' with
200
- | None -> return (Error (missing_uri () ))
201
- | Some scheme -> return (Ok (scheme, uri, domain))
202
- end
203
-
204
- let stat root_dir name dbg sr vdi =
201
+ let stat ?(persistent = true ) root_dir name dbg sr vdi =
205
202
let args = Storage.Volume.Types.Volume.Stat.In. make dbg sr vdi in
206
203
let args = Storage.Volume.Types.Volume.Stat.In. rpc_of_t args in
207
204
let open Deferred.Result.Monad_infix in
208
205
fork_exec_rpc root_dir (script root_dir name `Volume " Volume.stat" ) args Storage.Volume.Types.Volume.Stat.Out. t_of_rpc
209
206
>> = fun response ->
210
- choose_datapath response.Storage.Volume.Types. uri
207
+ (* We can only use a URI with a valid scheme, since we use the scheme
208
+ to name the datapath plugin. *)
209
+ let possible =
210
+ List. filter_map ~f: (fun x ->
211
+ let uri = Uri. of_string x in
212
+ match Uri. scheme uri with
213
+ | None -> None
214
+ | Some scheme -> Some (scheme, uri)
215
+ ) response.Storage.Volume.Types. uri in
216
+ (* We can only use URIs whose schemes correspond to registered plugins *)
217
+ let possible = List. filter ~f: (fun (scheme , _ ) -> Hashtbl. mem ! Datapath_plugins. table scheme) possible in
218
+ (* If we want to be non-persistent, we prefer if the datapath plugin supports it natively *)
219
+ let preference_order =
220
+ if persistent
221
+ then possible
222
+ else
223
+ let supports_nonpersistent, others = List. partition_map ~f: (fun (scheme , uri ) ->
224
+ if Datapath_plugins. supports_feature scheme _nonpersistent
225
+ then `Fst (scheme, uri) else `Snd (scheme, uri)
226
+ ) possible in
227
+ supports_nonpersistent @ others in
228
+ match preference_order with
229
+ | [] -> return (Error (missing_uri () ))
230
+ | (scheme , u ) :: us -> return (Ok (scheme, Uri. to_string u, " 0" ))
211
231
212
232
(* Process a message *)
213
233
let process root_dir name x =
@@ -268,6 +288,12 @@ let process root_dir name x =
268
288
" VDI_ATTACH" ; " VDI_DETACH" ; " VDI_ACTIVATE" ; " VDI_DEACTIVATE" ;
269
289
" VDI_INTRODUCE"
270
290
] in
291
+ (* If we have the ability to clone a disk then we can provide
292
+ clone on boot. *)
293
+ let features =
294
+ if List. mem features " VDI_CLONE"
295
+ then " VDI_RESET_ON_BOOT/2" :: features
296
+ else features in
271
297
let response = {
272
298
driver = response.Storage.Plugin.Types. plugin;
273
299
name = response.Storage.Plugin.Types. name;
@@ -593,19 +619,26 @@ let process root_dir name x =
593
619
Attached_SRs. find args.Args.VDI.Epoch_begin. sr
594
620
>> = fun sr ->
595
621
(* Discover the URIs using Volume.stat *)
596
- stat root_dir name
622
+ let persistent = args.Args.VDI.Epoch_begin. persistent in
623
+ stat ~persistent root_dir name
597
624
args.Args.VDI.Epoch_begin. dbg
598
625
sr
599
626
args.Args.VDI.Epoch_begin. vdi
600
627
>> = fun (datapath , uri , domain ) ->
601
- let persistent = args.Args.VDI.Epoch_begin. persistent in
602
- let args = Storage.Datapath.Types.Datapath.Open.In. make
603
- args.Args.VDI.Epoch_begin. dbg
604
- uri persistent in
605
- let args = Storage.Datapath.Types.Datapath.Open.In. rpc_of_t args in
606
- fork_exec_rpc root_dir (script root_dir name (`Datapath datapath) " Datapath.open" ) args Storage.Datapath.Types.Datapath.Open.Out. t_of_rpc
607
- >> = fun () ->
608
- Deferred.Result. return (R. success (Args.VDI.Epoch_begin. rpc_of_response () ))
628
+ (* If non-persistent and the datapath plugin supports NONPERSISTENT
629
+ then we delegate this to the datapath plugin. Otherwise we will
630
+ make a temporary clone now and attach/detach etc this file. *)
631
+ if Datapath_plugins. supports_feature datapath _nonpersistent then begin
632
+ let args = Storage.Datapath.Types.Datapath.Open.In. make
633
+ args.Args.VDI.Epoch_begin. dbg
634
+ uri persistent in
635
+ let args = Storage.Datapath.Types.Datapath.Open.In. rpc_of_t args in
636
+ fork_exec_rpc root_dir (script root_dir name (`Datapath datapath) " Datapath.open" ) args Storage.Datapath.Types.Datapath.Open.Out. t_of_rpc
637
+ >> = fun () ->
638
+ Deferred.Result. return (R. success (Args.VDI.Epoch_begin. rpc_of_response () ))
639
+ end else begin
640
+ Deferred. return (Error (backend_error " UNIMPLEMENTED" [ name ]))
641
+ end
609
642
| { R. name = "VDI.epoch_end" ; R. params = [ args ] } ->
610
643
let open Deferred.Result.Monad_infix in
611
644
let args = Args.VDI.Epoch_end. request_of_rpc args in
0 commit comments