WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-api

[Xen-API] [PATCH 1 of 2] Local disk caching API work. Added pool-level A

To: xen-api@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-API] [PATCH 1 of 2] Local disk caching API work. Added pool-level API calls to enable/disable caching, host-level API calls for same, per VDI on_boot and allow_caching parameters, and CLI calls for all
From: Jon Ludlam <jonathan.ludlam@xxxxxxxxxxxxx>
Date: Fri, 24 Sep 2010 17:31:34 +0100
Delivery-date: Fri, 24 Sep 2010 09:33:26 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
In-reply-to: <patchbomb.1285345893@xxxxxxxxxxxxxxxxxxxxxxxxxx>
List-help: <mailto:xen-api-request@lists.xensource.com?subject=help>
List-id: Discussion of API issues surrounding Xen <xen-api.lists.xensource.com>
List-post: <mailto:xen-api@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-api>, <mailto:xen-api-request@lists.xensource.com?subject=unsubscribe>
References: <patchbomb.1285345893@xxxxxxxxxxxxxxxxxxxxxxxxxx>
Sender: xen-api-bounces@xxxxxxxxxxxxxxxxxxx
User-agent: Mercurial-patchbomb/1.4.3
# HG changeset patch
# User Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>
# Date 1285345650 -3600
# Node ID 243ef81d48f72655dc409b127eb39785e4a5f5c0
# Parent  e8da99c62c3e9ae692285a3b5d016547bc503192
Local disk caching API work. Added pool-level API calls to enable/disable 
caching, host-level API calls for same, per VDI on_boot and allow_caching 
parameters, and CLI calls for all.

Signed-off-by: Jon Ludlam <Jonathan.Ludlam@xxxxxxxxxxxxx>

diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/client_records/record_util.ml
--- a/ocaml/client_records/record_util.ml
+++ b/ocaml/client_records/record_util.ml
@@ -324,6 +324,11 @@
 let i642sm_to_string sep x =
   String.concat sep (List.map (fun (a,b) -> Printf.sprintf "%Ld %s" a b) x)
 
+let on_boot_to_string onboot =
+       match onboot with
+               | `reset -> "reset"
+               | `persist -> "persist"
+
 (** Parse a string which might have a units suffix on the end *)
 let bytes_of_string field x = 
   let isdigit c = c >= '0' && c <= '9' in
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/client_records/records.ml
--- a/ocaml/client_records/records.ml
+++ b/ocaml/client_records/records.ml
@@ -1057,6 +1057,7 @@
     make_field ~name:"power-on-mode" ~get:(fun () -> (x 
()).API.host_power_on_mode) ();
     make_field ~name:"power-on-config" ~get:(fun () -> 
Record_util.s2sm_to_string "; " (x ()).API.host_power_on_config)
       ~get_map:(fun () -> (x ()).API.host_power_on_config) ();
+       make_field ~name:"local-cache-sr" ~get:(fun () -> get_uuid_from_ref (x 
()).API.host_local_cache_sr) ();
   ]}
 
 let vdi_record rpc session_id vdi =
@@ -1113,6 +1114,10 @@
       ~get_map:(fun () -> (x ()).API.vDI_xenstore_data) ();
     make_field ~name:"sm-config" ~get:(fun () -> Record_util.s2sm_to_string "; 
" (x ()).API.vDI_sm_config) 
       ~get_map:(fun () -> (x ()).API.vDI_sm_config) ();
+       make_field ~name:"on-boot" ~get:(fun () -> 
Record_util.on_boot_to_string (x ()).API.vDI_on_boot) 
+               ~set:(fun onboot -> Client.VDI.set_on_boot rpc session_id vdi 
(match onboot with "persist" -> `persist | "reset" -> `reset)) ();
+               make_field ~name:"allow-caching" ~get:(fun () -> string_of_bool 
(x ()).API.vDI_allow_caching) 
+               ~set:(fun b -> Client.VDI.set_allow_caching rpc session_id vdi 
(bool_of_string b)) ();
   ]}
 
 let vbd_record rpc session_id vbd =
@@ -1272,6 +1277,7 @@
     make_field ~name:"sm-config" ~get:(fun () -> Record_util.s2sm_to_string "; 
" (x ()).API.sR_sm_config) 
       ~get_map:(fun () -> (x ()).API.sR_sm_config) ();
     make_field ~name:"blobs" ~get:(fun () -> Record_util.s2brm_to_string 
get_uuid_from_ref "; " (x ()).API.sR_blobs) ();
+       make_field ~name:"local-cache-enabled" ~get:(fun () -> string_of_bool 
(x ()).API.sR_local_cache_enabled) ();
   ]}
     
 let pbd_record rpc session_id pbd =
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/idl/api_errors.ml
--- a/ocaml/idl/api_errors.ml
+++ b/ocaml/idl/api_errors.ml
@@ -62,6 +62,9 @@
 let host_is_slave = "HOST_IS_SLAVE"
 let host_name_invalid = "HOST_NAME_INVALID"
 let host_has_resident_vms = "HOST_HAS_RESIDENT_VMS"
+let hosts_failed_to_enable_caching = "HOSTS_FAILED_TO_ENABLE_CACHING"
+let hosts_failed_to_disable_caching = "HOSTS_FAILED_TO_DISABLE_CACHING"
+let host_cannot_see_SR = "HOST_CANNOT_SEE_SR"
 
 (* Host errors which explain why the host is in emergency mode *)
 let host_its_own_slave = "HOST_ITS_OWN_SLAVE"
@@ -181,6 +184,7 @@
 let vdi_incompatible_type = "VDI_INCOMPATIBLE_TYPE"
 let vdi_not_managed = "VDI_NOT_MANAGED"
 let vdi_io_error = "VDI_IO_ERROR"
+let vdi_on_boot_mode_incompatable_with_operation = 
"VDI_ON_BOOT_MODE_INCOMPATABLE_WITH_OPERATION"
 let cannot_create_state_file = "CANNOT_CREATE_STATE_FILE"
 
 
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/idl/datamodel.ml
--- a/ocaml/idl/datamodel.ml
+++ b/ocaml/idl/datamodel.ml
@@ -3653,6 +3653,28 @@
        ~hide_from_docs:true
        () 
   
+let host_enable_local_storage_caching = call ~flags:[`Session]
+       ~name:"enable_local_storage_caching"
+       ~in_product_since:rel_cowley
+       ~doc:"Enable the use of a local SR for caching purposes"
+       ~params:[
+               Ref _host, "host", "The host";
+               Ref _sr, "sr", "The SR to use as a local cache"
+       ]
+       ~allowed_roles:_R_POOL_OP
+       ()
+
+let host_disable_local_storage_caching = call ~flags:[`Session]
+       ~name:"disable_local_storage_caching"
+       ~in_product_since:rel_cowley
+       ~doc:"Disable the use of a local SR for caching purposes"
+       ~params:[
+               Ref _host, "host", "The host"
+       ]
+       ~allowed_roles:_R_POOL_OP
+       ()
+
+
 (** Hosts *)
 let host =
     create_obj ~in_db:true ~in_product_since:rel_rio 
~in_oss_since:oss_since_303 ~internal_deprecated_since:None 
~persist:PersistEverything ~gen_constructor_destructor:false ~name:_host 
~descr:"A physical host" ~gen_events:true
@@ -3726,6 +3748,8 @@
                 host_set_cpu_features;
                 host_reset_cpu_features;
                 host_reset_networking;
+                host_enable_local_storage_caching;
+                host_disable_local_storage_caching;
                 ]
       ~contents:
         ([ uid _host;
@@ -3767,7 +3791,7 @@
     field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride 
~default_value:(Some (VMap [])) ~ty:(Map (String,String)) "bios_strings" "BIOS 
strings";
        field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride 
~default_value:(Some (VString "")) ~ty:String "power_on_mode" "The power on 
mode";  
        field ~qualifier:DynamicRO ~in_product_since:rel_midnight_ride 
~default_value:(Some (VMap [])) ~ty:(Map(String, String)) "power_on_config" 
"The power on config";
-
+       field ~qualifier:DynamicRO ~in_product_since:rel_cowley 
~default_value:(Some (VRef (Ref.string_of Ref.null))) ~ty:(Ref _sr) 
"local_cache_sr" "The SR that is used as a local cache";
  ])
        ()
 
@@ -4430,6 +4454,7 @@
        field ~ty:Bool ~qualifier:DynamicRO ~in_oss_since:None 
~internal_only:true "default_vdi_visibility" "";
        field ~in_oss_since:None ~ty:(Map(String, String)) 
~in_product_since:rel_miami ~qualifier:RW "sm_config" "SM dependent data" 
~default_value:(Some (VMap []));
        field ~qualifier:DynamicRO ~in_product_since:rel_orlando 
~ty:(Map(String, Ref _blob)) ~default_value:(Some (VMap [])) "blobs" "Binary 
blobs associated with this SR";
+       field ~qualifier:DynamicRO ~in_product_since:rel_cowley ~ty:Bool 
~default_value:(Some (VBool false)) "local_cache_enabled" "True if this SR is 
assigned to be the local cache for its host";
       ])
        ()
 
@@ -4665,6 +4690,31 @@
    ~allowed_roles:_R_VM_ADMIN
    ()
 
+let on_boot = Enum ("on_boot", [ "reset", "The VDI will be reset to the state 
it was in at the last clone";
+"persist", "The VDIs contents are persistent" ])
+
+ let vdi_set_on_boot = call
+        ~name:"set_on_boot"
+        ~in_oss_since:None
+        ~in_product_since:rel_cowley
+        ~params:[Ref _vdi, "self", "The VDI to modify";
+                 on_boot, "value", "The value to set"]
+        ~doc:"Set the value of the on_boot parameter"
+        ~hide_from_docs:true
+        ~allowed_roles:_R_VM_ADMIN
+        ()
+
+let vdi_set_allow_caching = call
+       ~name:"set_allow_caching"
+       ~in_oss_since:None
+       ~in_product_since:rel_cowley
+       ~params:[Ref _vdi, "self", "The VDI to modify";
+       Bool, "value", "The value to set"]
+       ~doc:"Set the value of the allow_caching parameter"
+       ~hide_from_docs:true
+       ~allowed_roles:_R_VM_ADMIN
+       ()
+                         
 (** A virtual disk *)
 let vdi =
     create_obj ~in_db:true ~in_product_since:rel_rio 
~in_oss_since:oss_since_303 ~internal_deprecated_since:None 
~persist:PersistEverything ~gen_constructor_destructor:true ~name:_vdi 
~descr:"A virtual disk image"
@@ -4685,6 +4735,8 @@
                 vdi_set_virtual_size;
                 vdi_set_physical_utilisation;
                 vdi_generate_config;
+                vdi_set_on_boot;
+                vdi_set_allow_caching;
                ]
       ~contents:
       ([ uid _vdi;
@@ -4713,6 +4765,9 @@
        field ~in_product_since:rel_orlando                                     
         ~qualifier:DynamicRO ~ty:(Set (Ref _vdi)) "snapshots" "List pointing 
to all the VDIs snapshots.";
        field ~in_product_since:rel_orlando ~default_value:(Some (VDateTime 
Date.never)) ~qualifier:DynamicRO ~ty:DateTime         "snapshot_time" 
"Date/time when this snapshot was created.";
        field ~writer_roles:_R_VM_OP ~in_product_since:rel_orlando 
~default_value:(Some (VSet [])) ~ty:(Set String) "tags" "user-specified tags 
for categorization purposes";
+       field ~in_product_since:rel_cowley ~qualifier:DynamicRO ~ty:Bool 
~default_value:(Some (VBool false)) "allow_caching" "true if this VDI is to be 
cached in the local cache SR";
+       field ~in_product_since:rel_cowley ~qualifier:DynamicRO ~ty:on_boot 
~default_value:(Some (VEnum "persist")) "on_boot" "The behaviour of this VDI on 
a VM boot";
+       
       ])
        ()
 
@@ -5294,6 +5349,24 @@
   ~result:(String, "An XMLRPC result")
   ()
 
+let pool_enable_local_storage_caching = call 
+       ~name:"enable_local_storage_caching"
+       ~in_oss_since:None
+       ~in_product_since:rel_cowley
+       ~params:[Ref _pool, "self", "Reference to the pool"]
+       ~doc:"This call attempts to enable pool-wide local storage caching"
+       ~allowed_roles:_R_POOL_OP
+       ()
+
+let pool_disable_local_storage_caching = call 
+       ~name:"disable_local_storage_caching"
+       ~in_oss_since:None
+       ~in_product_since:rel_cowley
+       ~params:[Ref _pool, "self", "Reference to the pool"]
+       ~doc:"This call disables pool-wide local storage caching"
+       ~allowed_roles:_R_POOL_OP
+       ()
+
 (** A pool class *)
 let pool =
        create_obj
@@ -5356,6 +5429,8 @@
                        ; pool_audit_log_append
                        ; pool_set_vswitch_controller
                        ; pool_test_archive_target
+                       ; pool_enable_local_storage_caching
+                       ; pool_disable_local_storage_caching
                        ]
                ~contents:
                        [uid ~in_oss_since:None _pool
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/cli_frontend.ml
--- a/ocaml/xapi/cli_frontend.ml
+++ b/ocaml/xapi/cli_frontend.ml
@@ -450,6 +450,42 @@
       flags=[Host_selectors];
     };
 
+   "host-enable-local-storage-caching",
+       { 
+               reqd=["sr-uuid"];
+               optn=[];
+               help="Enable local storage caching on the specified host";
+               implementation=No_fd 
Cli_operations.host_enable_local_storage_caching;
+               flags=[Host_selectors];
+       };
+
+   "host-disable-local-storage-caching",
+       { 
+               reqd=[];
+               optn=[];
+               help="Disable local storage caching on the specified host";
+               implementation=No_fd 
Cli_operations.host_disable_local_storage_caching;
+               flags=[Host_selectors];
+       };
+         
+   "pool-enable-local-storage-caching",
+       {
+               reqd=["uuid"];
+               optn=[];
+               help="Enable local storage caching across the pool";
+               implementation=No_fd 
Cli_operations.pool_enable_local_storage_caching;
+               flags=[];
+       };
+
+   "pool-disable-local-storage-caching",
+       {
+               reqd=["uuid"];
+               optn=[];
+               help="Disable local storage caching across the pool";
+               implementation=No_fd 
Cli_operations.pool_disable_local_storage_caching;
+               flags=[];
+       };
+
    "host-shutdown",
     {
       reqd=[];
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/cli_operations.ml
--- a/ocaml/xapi/cli_operations.ml
+++ b/ocaml/xapi/cli_operations.ml
@@ -3338,6 +3338,23 @@
   in
   ignore(do_host_op rpc session_id op params [])
   
+let host_enable_local_storage_caching printer rpc session_id params =
+       ignore(do_host_op rpc session_id (fun _ host -> 
+               let sr_uuid = List.assoc "sr-uuid" params in
+               let sr = Client.SR.get_by_uuid rpc session_id sr_uuid in
+               Client.Host.enable_local_storage_caching rpc session_id 
(host.getref ()) sr
+       ) params ["sr-uuid"])
+
+let host_disable_local_storage_caching printer rpc session_id params =
+       ignore(do_host_op rpc session_id (fun _ host -> 
Client.Host.disable_local_storage_caching rpc session_id (host.getref ())) 
params [])
+
+let pool_enable_local_storage_caching printer rpc session_id params =
+       let pool = List.hd (Client.Pool.get_all rpc session_id) in
+       Client.Pool.enable_local_storage_caching rpc session_id pool
+       
+let pool_disable_local_storage_caching printer rpc session_id params =
+       let pool = List.hd (Client.Pool.get_all rpc session_id) in
+       Client.Pool.disable_local_storage_caching rpc session_id pool
   
 let host_set_power_on_mode printer rpc session_id params =
   let power_on_mode = List.assoc "power-on-mode" params in
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/message_forwarding.ml
--- a/ocaml/xapi/message_forwarding.ml
+++ b/ocaml/xapi/message_forwarding.ml
@@ -2184,6 +2184,14 @@
     let reset_networking ~__context ~host = 
       info "Host.reset_networking: host = '%s'" (host_uuid ~__context host);
       Local.Host.reset_networking ~__context ~host
+
+       let enable_local_storage_caching ~__context ~host ~sr =
+               let local_fn = Local.Host.enable_local_storage_caching ~host 
~sr in
+               do_op_on ~local_fn ~__context ~host (fun session_id rpc -> 
Client.Host.enable_local_storage_caching rpc session_id host sr)
+
+       let disable_local_storage_caching ~__context ~host =
+               let local_fn = Local.Host.disable_local_storage_caching ~host in
+               do_op_on ~local_fn ~__context ~host (fun session_id rpc -> 
Client.Host.disable_local_storage_caching rpc session_id host)
 end
 
   module Host_crashdump = struct
@@ -2793,6 +2801,24 @@
       Sm.assert_session_has_internal_sr_access ~__context ~sr;
       Local.VDI.set_physical_utilisation ~__context ~self ~value
 
+       let ensure_vdi_not_on_running_vm ~__context ~self =
+               let vbds = Db.VDI.get_VBDs ~__context ~self in
+               List.iter (fun vbd ->
+                       let vm = Db.VBD.get_VM ~__context ~self:vbd in
+                       let state = Db.VM.get_power_state ~__context ~self:vm in
+                       match state with
+                               | `Halted -> ()
+                               | _ -> raise 
(Api_errors.Server_error(Api_errors.vm_bad_power_state, 
+                                       [Ref.string_of vm; "halted"; 
Record_util.power_to_string state]))) vbds
+
+       let set_on_boot ~__context ~self ~value =
+               ensure_vdi_not_on_running_vm ~__context ~self;
+               Local.VDI.set_on_boot ~__context ~self ~value
+
+       let set_allow_caching ~__context ~self ~value =
+               ensure_vdi_not_on_running_vm ~__context ~self;
+               Local.VDI.set_allow_caching ~__context ~self ~value
+
     (* know sr so just use SR forwarding policy direct here *)
     let create ~__context ~name_label ~name_description ~sR ~virtual_size 
~_type ~sharable ~read_only ~other_config ~xenstore_data ~sm_config ~tags =
       info "VDI.create: SR = '%s'; name label = '%s'" (sr_uuid ~__context sR) 
name_label;
@@ -2912,7 +2938,7 @@
        (fun () ->
           forward_vdi_op ~local_fn ~__context ~self:vdi
             (fun session_id rpc -> Client.VDI.force_unlock rpc session_id vdi))
-       
+
   end
   module VBD = struct
 
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/sm_exec.ml
--- a/ocaml/xapi/sm_exec.ml
+++ b/ocaml/xapi/sm_exec.ml
@@ -57,10 +57,14 @@
   vdi_ref: API.ref_VDI option;
   vdi_location: string option;
   vdi_uuid: string option;
+  vdi_on_boot: string option;
+  vdi_allow_caching : string option;
 
   (* Reference to the task which performs the call *)
   subtask_of: API.ref_task option;
 
+  local_cache_sr: string option;
+
   cmd: string;
   args: string list;
 }
@@ -73,6 +77,10 @@
         then vdi_location
         else may (fun self -> Db.VDI.get_location ~__context ~self) vdi_ref in
        let vdi_uuid = may (fun self -> Db.VDI.get_uuid ~__context ~self) 
vdi_ref in
+          let vdi_on_boot = may (fun self -> 
+                  match Db.VDI.get_on_boot ~__context ~self with `persist -> 
"persist" | `reset -> "reset") vdi_ref in
+          let vdi_allow_caching = may (fun self -> string_of_bool 
(Db.VDI.get_allow_caching ~__context ~self)) vdi_ref in
+          let local_cache_sr = try Some (Db.SR.get_uuid ~__context 
~self:(Db.Host.get_local_cache_sr ~__context ~self:(Helpers.get_localhost 
__context))) with _ -> None in
        let sr_uuid = may (fun self -> Db.SR.get_uuid ~__context ~self) sr_ref 
in
        { host_ref = !Xapi_globs.localhost_ref;
         session_ref = None; (* filled in at the last minute *)
@@ -85,8 +93,11 @@
         vdi_ref = vdi_ref;
         vdi_location = vdi_location;
         vdi_uuid = vdi_uuid;
+        vdi_on_boot = vdi_on_boot;
+        vdi_allow_caching = vdi_allow_caching;
         new_uuid = new_uuid;
         subtask_of = subtask_of;
+        local_cache_sr = local_cache_sr;
         cmd = cmd;
         args = args
        })
@@ -108,13 +119,15 @@
   let vdi_ref = default [] (may (fun x -> [ "vdi_ref", XMLRPC.To.string 
(Ref.string_of x) ]) call.vdi_ref) in
   let vdi_location = default [] (may (fun x -> [ "vdi_location", 
XMLRPC.To.string x ]) call.vdi_location) in
   let vdi_uuid = default [] (may (fun x -> [ "vdi_uuid", XMLRPC.To.string x ]) 
call.vdi_uuid) in
+  let vdi_on_boot = default [] (may (fun x -> [ "vdi_on_boot", 
XMLRPC.To.string x ]) call.vdi_on_boot) in
+  let vdi_allow_caching = default [] (may (fun x -> [ "vdi_allow_caching", 
XMLRPC.To.string x ]) call.vdi_allow_caching) in
   let new_uuid = default [] (may (fun x -> [ "new_uuid", XMLRPC.To.string x ]) 
call.new_uuid) in
 
   let driver_params = default [] (may (fun x -> [ "driver_params", kvpairs x 
]) call.driver_params) in
   let vdi_sm_config = default [] (may (fun x -> [ "vdi_sm_config", kvpairs x 
]) call.vdi_sm_config) in
   let subtask_of = default [] (may (fun x -> [ "subtask_of", XMLRPC.To.string 
(Ref.string_of x) ]) call.subtask_of) in
-
-  let all = common @ dc @ session_ref @ sr_sm_config @ sr_ref @ sr_uuid @ 
vdi_ref @ vdi_location @ vdi_uuid @ driver_params @ vdi_sm_config @ new_uuid @ 
subtask_of in
+  let local_cache_sr = default [] (may (fun x -> ["local_cache_sr", 
XMLRPC.To.string x]) call.local_cache_sr) in
+  let all = common @ dc @ session_ref @ sr_sm_config @ sr_ref @ sr_uuid @ 
vdi_ref @ vdi_location @ vdi_uuid @ driver_params @ vdi_sm_config @ new_uuid @ 
subtask_of @ vdi_on_boot @ vdi_allow_caching @ local_cache_sr in
   XMLRPC.To.methodCall call.cmd [ XMLRPC.To.structure all ]
 
 let methodResponse xml =
@@ -260,6 +273,7 @@
   let lookup_table = 
     [ "SR_PROBE",       Sr_probe;
       "SR_UPDATE",      Sr_update;
+         "SR_SUPPORTS_LOCAL_CACHING", Sr_supports_local_caching;
       "VDI_CREATE",     Vdi_create;
       "VDI_DELETE",     Vdi_delete;
       "VDI_ATTACH",     Vdi_attach;
@@ -273,6 +287,7 @@
       "VDI_UPDATE",     Vdi_update;
       "VDI_INTRODUCE",  Vdi_introduce;
       "VDI_GENERATE_CONFIG", Vdi_generate_config;
+         "VDI_RESET_ON_BOOT", Vdi_reset_on_boot;
     ] in
   let strings = XMLRPC.From.array XMLRPC.From.string (safe_assoc 
"capabilities" info) in
   List.iter (fun s -> 
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/smint.ml
--- a/ocaml/xapi/smint.ml
+++ b/ocaml/xapi/smint.ml
@@ -32,15 +32,18 @@
 
 (** Very primitive first attempt at a set of backend capabilities *)
 type capability =
-    | Sr_create | Sr_delete | Sr_attach | Sr_detach | Sr_scan | Sr_probe | 
Sr_update
+    | Sr_create | Sr_delete | Sr_attach | Sr_detach | Sr_scan | Sr_probe | 
Sr_update 
+       | Sr_supports_local_caching
     | Vdi_create | Vdi_delete | Vdi_attach | Vdi_detach
     | Vdi_clone | Vdi_snapshot | Vdi_resize | Vdi_activate | Vdi_deactivate
     | Vdi_update | Vdi_introduce 
     | Vdi_resize_online
     | Vdi_generate_config
+       | Vdi_reset_on_boot
 
 let all_capabilities =
   [ Sr_create; Sr_delete; Sr_attach; Sr_detach; Sr_scan; Sr_probe; Sr_update;
+    Sr_supports_local_caching; 
     Vdi_create; Vdi_delete; Vdi_attach; Vdi_detach;
     Vdi_clone; Vdi_resize; Vdi_activate; Vdi_deactivate;
     Vdi_update; Vdi_introduce;
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_host.ml
--- a/ocaml/xapi/xapi_host.ml
+++ b/ocaml/xapi/xapi_host.ml
@@ -96,8 +96,14 @@
     end
 
 (** Check that a) there are no running VMs present on the host, b) there are 
no VBDs currently 
-    attached to dom0, and c) that there are no tasks running *)
-let assert_can_shutdown ~__context ~host =
+    attached to dom0, c) host is disabled.
+
+       This is approximately maintainance mode as defined by the gui. However, 
since 
+       we haven't agreed on an exact definition of this mode, we'll not call 
this maintainance mode here, but we'll
+       use a synonym. According to http://thesaurus.com/browse/maintenance, 
bacon is a synonym 
+       for maintainance, hence the name of the following function.
+*)
+let assert_bacon_mode ~__context ~host =
   if Db.Host.get_enabled ~__context ~self:host 
   then raise (Api_errors.Server_error (Api_errors.host_not_disabled, []));
 
@@ -107,14 +113,14 @@
   (* We always expect a control domain to be resident on a host *)
   if List.length vms > 1 then
     raise (Api_errors.Server_error (Api_errors.host_in_use, [ selfref; "vm"; 
List.hd (List.map Ref.string_of vms) ]));
-  debug "Shutdown test: VMs OK - %d running VMs" (List.length vms);
+  debug "Bacon test: VMs OK - %d running VMs" (List.length vms);
   let controldomain = List.find (fun vm -> Db.VM.get_resident_on ~__context 
~self:vm = host &&
       Db.VM.get_is_control_domain ~__context ~self:vm) (Db.VM.get_all 
~__context) in  
   let vbds = List.filter (fun vbd -> Db.VBD.get_VM ~__context ~self:vbd = 
controldomain &&
       Db.VBD.get_currently_attached ~__context ~self:vbd) (Db.VBD.get_all 
~__context) in
   if List.length vbds > 0 then
     raise (Api_errors.Server_error (Api_errors.host_in_use, [ selfref; "vbd"; 
List.hd (List.map Ref.string_of vbds) ]));
-  debug "Shutdown test: VBDs OK"
+  debug "Bacon test: VBDs OK"
 
 let pif_update_dhcp_address ~__context ~self =
   let network = Db.PIF.get_network ~__context ~self in
@@ -463,7 +469,7 @@
   end
 
 let shutdown_and_reboot_common ~__context ~host label description operation 
cmd = 
-  assert_can_shutdown ~__context ~host;
+  assert_bacon_mode ~__context ~host;
   Xapi_ha.before_clean_shutdown_or_reboot ~__context ~host;
   Remote_requests.stop_request_thread();
 
@@ -648,6 +654,7 @@
     ~bios_strings:[]
     ~power_on_mode:""
     ~power_on_config:[]
+         ~local_cache_sr:Ref.null
   ;
   (* If the host we're creating is us, make sure its set to live *)
   Db.Host_metrics.set_last_updated ~__context ~self:metrics 
~value:(Date.of_float (Unix.gettimeofday ()));
@@ -1354,3 +1361,31 @@
        let physical_features = List.assoc "physical_features" cpu_info in
        let cpu_info = List.replace_assoc "features_after_reboot" 
physical_features cpu_info in
        Db.Host.set_cpu_info ~__context ~self:host ~value:cpu_info
+
+let enable_local_storage_caching ~__context ~host ~sr =
+       assert_bacon_mode ~__context ~host;
+       let ty = Db.SR.get_type ~__context ~self:sr in
+       let pbds = Db.SR.get_PBDs ~__context ~self:sr in
+       let shared = Db.SR.get_shared ~__context ~self:sr in
+       let has_required_capability = 
+               let caps = Sm.capabilities_of_driver ty in
+               List.mem Smint.Sr_supports_local_caching caps
+       in
+       debug "shared: %b. List.length pbds: %d. has_required_capability: %b" 
shared (List.length pbds) has_required_capability;
+       if (shared=false) && (List.length pbds = 1) && has_required_capability 
then begin
+               let pbd_host = Db.PBD.get_host ~__context ~self:(List.hd pbds) 
in
+               if pbd_host <> host then raise (Api_errors.Server_error 
(Api_errors.host_cannot_see_SR,[Ref.string_of host; Ref.string_of sr]));
+               Db.Host.set_local_cache_sr ~__context ~self:host ~value:sr;
+               Db.SR.set_local_cache_enabled ~__context ~self:sr ~value:true
+       end else begin
+               raise (Api_errors.Server_error 
(Api_errors.sr_operation_not_supported,[]))
+       end
+
+let disable_local_storage_caching ~__context ~host =
+       assert_bacon_mode ~__context ~host;
+       let sr = Db.Host.get_local_cache_sr ~__context ~self:host in
+       Db.Host.set_local_cache_sr ~__context ~self:host ~value:Ref.null;
+       try Db.SR.set_local_cache_enabled ~__context ~self:sr ~value:false with 
_ -> () 
+
+
+               
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_host.mli
--- a/ocaml/xapi/xapi_host.mli
+++ b/ocaml/xapi/xapi_host.mli
@@ -252,6 +252,10 @@
 (** Remove the feature mask, such that after a reboot all features of the CPU 
are enabled. *)
 val reset_cpu_features : __context:Context.t -> host:API.ref_host -> unit
 
+(** Control the local caching behaviour of the host *)
+val enable_local_storage_caching : __context:Context.t -> host:API.ref_host -> 
sr:API.ref_SR -> unit
+val disable_local_storage_caching : __context:Context.t -> host:API.ref_host 
-> unit
+
 (** Purge all network-related metadata associated with the given host. *)
 val reset_networking : __context:Context.t -> host:API.ref_host -> unit
 
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_pool.ml
--- a/ocaml/xapi/xapi_pool.ml
+++ b/ocaml/xapi/xapi_pool.ml
@@ -16,6 +16,7 @@
 open Pervasiveext
 open Threadext
 open Stringext
+open Listext
 
 module L = Debug.Debugger(struct let name="license" end)
 module D=Debug.Debugger(struct let name="xapi" end)
@@ -1464,4 +1465,50 @@
     "test_archive_target"
     config
 
-               
+let enable_local_storage_caching ~__context ~self =
+    let srs = Db.SR.get_all_records ~__context in
+       let pbds = Db.PBD.get_all_records ~__context in
+       let hosts = Db.Host.get_all ~__context in
+
+       (* Exception handler is to cope with transient PBDs with invalid 
references *)
+       let hosts_and_srs = List.filter_map (fun (pbdref,pbdrec) -> 
+               try Some (pbdrec.API.pBD_host, pbdrec.API.pBD_SR, List.assoc 
pbdrec.API.pBD_SR srs) with _ -> None) pbds 
+       in
+       
+       let acceptable = List.filter (fun (href,srref,srrec) -> 
+               (not srrec.API.sR_shared) && 
+                       (List.length srrec.API.sR_PBDs = 1) && 
+                       (List.mem Smint.Sr_supports_local_caching 
(Sm.capabilities_of_driver srrec.API.sR_type))
+       ) hosts_and_srs in
+
+       let failed_hosts = 
+               Helpers.call_api_functions ~__context
+                       (fun rpc session_id -> 
+                               let failed = List.filter_map (fun host ->
+                                       let result = ref (Some host) in
+                                       let acceptable_srs = List.filter (fun 
(href,srref,srrec) -> href=host) acceptable in
+                                       List.iter (fun (href,ref,sr) -> 
+                                               try 
Client.Host.enable_local_storage_caching rpc session_id host ref; result := 
None with _ -> ()) acceptable_srs;
+                                       !result
+                               ) hosts in
+                               failed)
+       in
+       if List.length failed_hosts > 0 then 
+               raise (Api_errors.Server_error 
(Api_errors.hosts_failed_to_enable_caching, List.map Ref.string_of 
failed_hosts))
+       else ()
+
+               
+let disable_local_storage_caching ~__context ~self =
+       let hosts = Db.Host.get_all ~__context in
+       let failed_hosts = Helpers.call_api_functions ~__context
+               (fun rpc session_id -> 
+                       List.filter_map (fun host -> 
+                               try 
+                                       
Client.Host.disable_local_storage_caching ~rpc ~session_id ~host;
+                                       None
+                               with _ -> 
+                                       Some host) hosts)
+       in
+       if List.length failed_hosts > 0 then
+               raise (Api_errors.Server_error 
(Api_errors.hosts_failed_to_disable_caching, List.map Ref.string_of 
failed_hosts))
+       else ()
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_pool.mli
--- a/ocaml/xapi/xapi_pool.mli
+++ b/ocaml/xapi/xapi_pool.mli
@@ -194,3 +194,5 @@
 val audit_log_append : __context:Context.t -> line:string -> unit
 
 val test_archive_target : __context:Context.t -> self:API.ref_pool -> 
config:API.string_to_string_map -> string
+val enable_local_storage_caching : __context:Context.t -> self:API.ref_pool -> 
unit
+val disable_local_storage_caching : __context:Context.t -> self:API.ref_pool 
-> unit
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_sr.ml
--- a/ocaml/xapi/xapi_sr.ml
+++ b/ocaml/xapi/xapi_sr.ml
@@ -232,7 +232,7 @@
       ~physical_size: (-1L)
       ~content_type
       ~_type ~shared ~other_config:[] ~default_vdi_visibility:true
-      ~sm_config ~blobs:[] ~tags:[] in
+      ~sm_config ~blobs:[] ~tags:[] ~local_cache_enabled:false in
 
     update_allowed_operations ~__context ~self:sr_ref;
     (* Return ref of newly created sr *)
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_vdi.ml
--- a/ocaml/xapi/xapi_vdi.ml
+++ b/ocaml/xapi/xapi_vdi.ml
@@ -30,6 +30,9 @@
   let _ref = Ref.string_of _ref' in
   let current_ops = record.Db_actions.vDI_current_operations in
   let vdi_is_sharable = record.Db_actions.vDI_sharable in
+
+  let reset_on_boot = record.Db_actions.vDI_on_boot = `reset in
+
   (* Policy:
      1. any current_operation implies exclusivity; fail everything else
      2. if doing a VM start then assume the sharing check is done elsewhere
@@ -111,6 +114,8 @@
          else None         
          | `snapshot when record.Db_actions.vDI_sharable ->
                        Some (Api_errors.vdi_is_sharable, [ _ref ])
+         | `snapshot when reset_on_boot ->
+                   Some 
(Api_errors.vdi_on_boot_mode_incompatable_with_operation, [])
       | _ -> None
     )
 
@@ -236,7 +241,8 @@
     ~physical_utilisation:(-1L) ~_type
     ~sharable ~read_only
     ~xenstore_data ~sm_config
-    ~other_config ~storage_lock:false ~location ~managed:true ~missing:false 
~parent:Ref.null ~tags:[];
+    ~other_config ~storage_lock:false ~location ~managed:true ~missing:false 
~parent:Ref.null ~tags:[]
+         ~on_boot:`persist ~allow_caching:false;
   ref
 
 let internal_db_introduce ~__context ~uuid ~name_label ~name_description ~sR 
~_type ~sharable ~read_only ~other_config ~location ~xenstore_data ~sm_config =
@@ -330,6 +336,9 @@
   Db.VDI.set_sharable ~__context ~self:newvdi ~value:a.Db_actions.vDI_sharable;
   Db.VDI.set_other_config ~__context ~self:newvdi 
~value:a.Db_actions.vDI_other_config;
   Db.VDI.set_xenstore_data ~__context ~self:newvdi 
~value:a.Db_actions.vDI_xenstore_data;
+  Db.VDI.set_on_boot ~__context ~self:newvdi ~value:a.Db_actions.vDI_on_boot;
+  Db.VDI.set_allow_caching ~__context ~self:newvdi 
~value:a.Db_actions.vDI_allow_caching;
+
   (* Record the fact this is a snapshot *)
  
   (*(try Db.VDI.remove_from_other_config ~__context ~self:newvdi 
~key:Xapi_globs.snapshot_of with _ -> ());
@@ -421,6 +430,8 @@
     Db.VDI.set_sharable ~__context ~self:newvdi 
~value:a.Db_actions.vDI_sharable;
     Db.VDI.set_other_config ~__context ~self:newvdi 
~value:a.Db_actions.vDI_other_config;
     Db.VDI.set_xenstore_data ~__context ~self:newvdi 
~value:a.Db_actions.vDI_xenstore_data;
+       Db.VDI.set_on_boot ~__context ~self:newvdi 
~value:a.Db_actions.vDI_on_boot;
+       Db.VDI.set_allow_caching ~__context ~self:newvdi 
~value:a.Db_actions.vDI_allow_caching;
 
     update_allowed_operations ~__context ~self:newvdi;
     newvdi
@@ -467,7 +478,7 @@
   let dst =
     Helpers.call_api_functions ~__context
       (fun rpc session_id ->
-        Client.VDI.create ~rpc ~session_id
+       let result = Client.VDI.create ~rpc ~session_id
           ~name_label:src.API.vDI_name_label
           ~name_description:src.API.vDI_name_description
           ~sR:sr
@@ -477,9 +488,15 @@
           ~read_only:src.API.vDI_read_only
           ~other_config:src.API.vDI_other_config
           ~xenstore_data:src.API.vDI_xenstore_data
-          ~sm_config:src.API.vDI_sm_config ~tags:[]
+          ~sm_config:src.API.vDI_sm_config ~tags:[] in
+    if src.API.vDI_on_boot = `reset then begin
+               try Client.VDI.set_on_boot ~rpc ~session_id ~self:result 
~value:(`reset) with _ -> ()
+       end;
+       result
       ) in
   try
+       Db.VDI.set_allow_caching ~__context ~self:dst 
~value:src.API.vDI_allow_caching;
+
     Sm_fs_ops.copy_vdi ~__context vdi dst;
 
     Db.VDI.remove_from_current_operations ~__context ~self:dst ~key:task_id;
@@ -514,3 +531,24 @@
 
 let set_physical_utilisation ~__context ~self ~value = 
   Db.VDI.set_physical_utilisation ~__context ~self ~value
+
+let set_on_boot ~__context ~self ~value =
+       let sr = Db.VDI.get_SR ~__context ~self in
+       let ty = Db.SR.get_type ~__context ~self:sr in
+       let caps = Sm.capabilities_of_driver ty in
+       if not (List.mem Smint.Vdi_reset_on_boot caps) then 
+               raise 
(Api_errors.Server_error(Api_errors.sr_operation_not_supported,[Ref.string_of 
sr]));
+       Sm.assert_pbd_is_plugged ~__context ~sr;
+       Sm.call_sm_vdi_functions ~__context ~vdi:self
+               (fun srconf srtype sr ->
+                       let vdi_info = Sm.vdi_clone srconf srtype [] __context 
sr self in
+                       let uuid = require_uuid vdi_info in
+                       let ref = Db.VDI.get_by_uuid ~__context ~uuid in
+                       Sm.vdi_delete srconf srtype sr ref);
+       Db.VDI.set_on_boot ~__context ~self ~value
+
+let set_allow_caching ~__context ~self ~value =
+       Db.VDI.set_allow_caching ~__context ~self ~value
+
+       
+               
diff -r e8da99c62c3e -r 243ef81d48f7 ocaml/xapi/xapi_vm_lifecycle.ml
--- a/ocaml/xapi/xapi_vm_lifecycle.ml
+++ b/ocaml/xapi/xapi_vm_lifecycle.ml
@@ -16,6 +16,7 @@
  *)
 
 open Xapi_pv_driver_version
+open Listext
 
 module D = Debug.Debugger(struct let name="xapi" end)
 open D
@@ -202,7 +203,7 @@
 
 (** Take an internal VM record and a proposed operation, return true if the 
operation
     would be acceptable *)
-let check_operation_error ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled ~op =
+let check_operation_error ~vmr ~vmgmr ~ref ~clone_suspended_vm_enabled 
vdis_reset_and_caching ~op =
        let ref_str = Ref.string_of ref in
        let power_state = vmr.Db_actions.vM_power_state in
        let current_ops = vmr.Db_actions.vM_current_operations in
@@ -245,6 +246,18 @@
                && op <> `changing_dynamic_range
        then Some (Api_errors.operation_not_allowed, ["Operations on domain 0 
are not allowed"])
 
+       (* Check for an error due to VDI caching/reset behaviour *)
+       else if op = `checkpoint || op = `snapshot || op = `suspend || op = 
`snapshot_with_quiesce
+       then (* If any vdi exists with on_boot=reset, then disallow checkpoint, 
snapshot, suspend *)
+               if List.exists fst vdis_reset_and_caching 
+               then Some 
(Api_errors.vdi_on_boot_mode_incompatable_with_operation,[]) 
+               else None
+       else if op = `pool_migrate then
+               (* If any vdi exists with on_boot=reset and caching is enabled, 
disallow migrate *)
+               if List.exists (fun (reset,caching) -> reset && caching) 
vdis_reset_and_caching
+               then Some 
(Api_errors.vdi_on_boot_mode_incompatable_with_operation,[]) 
+               else None
+
        (* check PV drivers constraints if needed *)
        else if need_pv_drivers_check ~power_state ~op
        then check_drivers ~vmr ~vmgmr ~op ~ref
@@ -271,24 +284,32 @@
        let all = Db.VM.get_record_internal ~__context ~self in
        let gm = maybe_get_guest_metrics ~__context 
~ref:(all.Db_actions.vM_guest_metrics) in
        let clone_suspended_vm_enabled = Helpers.clone_suspended_vm_enabled 
~__context in
-       all, gm, clone_suspended_vm_enabled
+       let vdis_reset_and_caching = List.filter_map (fun vbd -> 
+               try 
+                       let vdi = Db.VBD.get_VDI ~__context ~self:vbd in
+               let sm_config = Db.VDI.get_sm_config ~__context ~self:vdi in
+                       Some 
+                               ((try List.assoc "on_boot" sm_config = "reset" 
with _ -> false),
+                               (try String.lowercase (List.assoc "caching" 
sm_config) = "true" with _ -> false))
+               with _ -> None) all.Db_actions.vM_VBDs in       
+       all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching
 
 let is_operation_valid ~__context ~self ~op =
-       let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
-       match check_operation_error all gm self clone_suspended_vm_enabled op 
with
+       let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = 
get_info ~__context ~self in
+       match check_operation_error all gm self clone_suspended_vm_enabled 
vdis_reset_and_caching op with
        | None   -> true
        | Some _ -> false
 
 let assert_operation_valid ~__context ~self ~op =
-       let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
-       match check_operation_error all gm self clone_suspended_vm_enabled op 
with
+       let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = 
get_info ~__context ~self in
+       match check_operation_error all gm self clone_suspended_vm_enabled 
vdis_reset_and_caching op with
        | None       -> ()
        | Some (a,b) -> raise (Api_errors.Server_error (a,b))
 
 let update_allowed_operations ~__context ~self =
-       let all, gm, clone_suspended_vm_enabled = get_info ~__context ~self in
+       let all, gm, clone_suspended_vm_enabled, vdis_reset_and_caching = 
get_info ~__context ~self in
        let check accu op =
-               match check_operation_error all gm self 
clone_suspended_vm_enabled op with
+               match check_operation_error all gm self 
clone_suspended_vm_enabled vdis_reset_and_caching op with
                | None -> op :: accu
                | _    -> accu
        in

Attachment: xen-api2.hg-1.patch
Description: Text Data

_______________________________________________
xen-api mailing list
xen-api@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/mailman/listinfo/xen-api
<Prev in Thread] Current Thread [Next in Thread>