[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[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



# 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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.