]> xenbits.xensource.com Git - xcp/xen-api.git/commitdiff
CP-1981: Track the vdi_activations in the local database
authorJon Ludlam <jonathan.ludlam@eu.citrix.com>
Wed, 26 Jan 2011 17:39:04 +0000 (17:39 +0000)
committerJon Ludlam <jonathan.ludlam@eu.citrix.com>
Wed, 26 Jan 2011 17:39:04 +0000 (17:39 +0000)
The 'locks' for the VDIs, which are maintained by the SM backends now, are stored in xapi's database. In the event of a master failover, the pool database may revert to a previous backup, which is then resynced with reality. Unfortunately there's no logic to resync the SM backends' data, nor any hook point to do this. Ideally, the SM backends would store their critical data internally somehow, but until this happens xapi will have to contain the important logic to resynchronise these locks.

This patch maintains a list of the VDIs that have been activatedi (including RW/RO mode) in the local database.

Signed-off-by: Jon Ludlam <jonathan.ludlam@eu.citrix.com>
ocaml/xapi/OMakefile
ocaml/xapi/sm.ml
ocaml/xapi/xapi.ml
ocaml/xapi/xapi_local_vdi_state.ml [new file with mode: 0644]
ocaml/xapi/xapi_local_vdi_state.mli [new file with mode: 0644]

index 800036cb833b436f14e730241df6aad3a4e20a59..9416156b43e9c8bd4d0ede99ffd259fba75cfea7 100644 (file)
@@ -151,6 +151,7 @@ XAPI_MODULES = $(COMMON) \
        binpack \
        xapi_local_session \
        xapi_local_pbd_state \
+       xapi_local_vdi_state \
        xha_interface \
        xha_statefile \
        xha_metadata_vdi \
index 99de187a39406e04de94d95956df3fcbd5bb40cc..25c8365a35082a4147b4d2a09bc88b968bbc2e1c 100644 (file)
@@ -159,12 +159,20 @@ let vdi_detach dconf driver sr vdi =
 let vdi_activate dconf driver sr vdi writable =
   debug "vdi_activate" driver (sprintf "sr=%s vdi=%s" (Ref.string_of sr) (Ref.string_of vdi));
   let call = Sm_exec.make_call ~sr_ref:sr ~vdi_ref:vdi dconf "vdi_activate" [ sprintf "%b" writable ] in
-  Sm_exec.parse_unit (Sm_exec.exec_xmlrpc (driver_type driver)  (driver_filename driver) call)
+  let Some loc = call.Sm_exec.vdi_location in 
+  Xapi_local_vdi_state.activate loc writable;
+  try 
+         Sm_exec.parse_unit (Sm_exec.exec_xmlrpc (driver_type driver)  (driver_filename driver) call)
+  with e ->
+         Xapi_local_vdi_state.deactivate loc;
+         raise e
                        
 let vdi_deactivate dconf driver sr vdi =
   debug "vdi_deactivate" driver (sprintf "sr=%s vdi=%s" (Ref.string_of sr) (Ref.string_of vdi));
   let call = Sm_exec.make_call ~sr_ref:sr ~vdi_ref:vdi dconf "vdi_deactivate" [] in
-  Sm_exec.parse_unit (Sm_exec.exec_xmlrpc (driver_type driver)  (driver_filename driver) call)
+  let Some loc = call.Sm_exec.vdi_location in
+  Sm_exec.parse_unit (Sm_exec.exec_xmlrpc (driver_type driver)  (driver_filename driver) call);
+  Xapi_local_vdi_state.deactivate loc
 
 let vdi_snapshot dconf driver driver_params sr vdi =
   debug "vdi_snapshot" driver (sprintf "sr=%s vdi=%s driver_params=[%s]" (Ref.string_of sr) (Ref.string_of vdi) (String.concat "; " (List.map (fun (k, v) -> k ^ "=" ^ v) driver_params)));
index 0f6ff995bb33c685ac674a032b9b68b6398e3d79..d5add7bafc4eb5d0e1fca62267689ed81d79d8cb 100644 (file)
@@ -343,7 +343,10 @@ let init_local_database () =
   (* We've just rebooted, so we clear the flag that stops the host being disabled during the reboot *)
   if !Xapi_globs.on_system_boot then Localdb.put Constants.host_disabled_until_reboot "false";
   (* After a reboot we assume all PBDs have currently_attached = false *)
-  if !Xapi_globs.on_system_boot then Xapi_local_pbd_state.clear ()
+  if !Xapi_globs.on_system_boot then Xapi_local_pbd_state.clear ();
+
+  (* Ditto for VDIs *)
+  if !Xapi_globs.on_system_boot then Xapi_local_vdi_state.clear ()
 
 
 let bring_up_management_if ~__context () = 
diff --git a/ocaml/xapi/xapi_local_vdi_state.ml b/ocaml/xapi/xapi_local_vdi_state.ml
new file mode 100644 (file)
index 0000000..7f0c793
--- /dev/null
@@ -0,0 +1,84 @@
+(* Some functions to record vdi_activates in the local database such that, in the
+   event of a pool-master change (and possible subsequent reversion of the database)
+   we can resynchronise the VDI.sm_config fields relating to attachment *)
+
+(* Note that when the SM backends can manage this themselves, this code should be
+   removed *)
+
+(* We could augment this to include attachments as well as activations. This could then
+   be used as input to the refcounting code, to help prevent a leaked attachment *)
+
+open Stringext
+open Threadext
+
+module StringSet = Set.Make(String)
+
+module D=Debug.Debugger(struct let name="xapi_local_vdi_state" end)
+open D
+
+(* The local database keys to use *)
+let key_ro = "vdi_activations_ro"
+let key_rw = "vdi_activations_rw"
+
+(* Perform all mutations holding this lock *)
+let lock = Mutex.create () 
+
+(* Marshalling/unmarshalling *)
+let set_of_string str = 
+       let t x = match String_unmarshall_helper.set (fun x -> x) x with
+               | [ r ] -> r
+               | _ -> failwith (Printf.sprintf "Failed to parse VDI location info from local database: %s" x) in
+       try 
+               let list = String_unmarshall_helper.set t str in
+               List.fold_left (fun set elt -> StringSet.add elt set) StringSet.empty list
+       with e ->
+               error "Unexpected error in Xapi_local_vdi_state.set_of_string: %s" (Printexc.to_string e);
+               StringSet.empty
+
+let string_of_set set =
+       let list = StringSet.fold (fun elt list -> elt::list) set [] in 
+       let t x = String_marshall_helper.set (fun x -> x) [ x ] in
+       String_marshall_helper.set t list
+
+(* Helper function *)
+let mutate rw f =
+       let key = if rw then key_rw else key_ro in
+       Mutex.execute lock (fun () ->   
+               let cur = Localdb.get_with_default key "()" in
+               let set = set_of_string cur in
+               let newset = f set in
+               let value = string_of_set newset in
+               Localdb.put key value)
+
+(* Exposed functions *)
+let activate location rw =
+       mutate rw (fun set -> StringSet.add location set)
+
+let deactivate location =
+       mutate true (fun set -> StringSet.remove location set);
+       mutate false (fun set -> StringSet.remove location set)
+
+let clear () =
+       mutate true (fun _ -> StringSet.empty);
+       mutate false (fun _ -> StringSet.empty)
+
+let iter f =
+       let (set_ro, set_rw) = Mutex.execute lock (fun () ->
+               let get key = 
+                       let cur = Localdb.get_with_default key "()" in 
+                       set_of_string cur 
+               in
+               (get key_ro, get key_rw)
+       ) in
+       StringSet.iter (f false) set_ro;
+       StringSet.iter (f true) set_rw
+
+let fold f x =
+       let (set_ro, set_rw) = Mutex.execute lock (fun () -> 
+               let get key = 
+                       let cur = Localdb.get_with_default key "()" in
+                       set_of_string cur
+               in
+               (get key_ro, get key_rw)
+       ) in
+       StringSet.fold (f true) set_rw (StringSet.fold (f false) set_ro x)
diff --git a/ocaml/xapi/xapi_local_vdi_state.mli b/ocaml/xapi/xapi_local_vdi_state.mli
new file mode 100644 (file)
index 0000000..8dc4b8e
--- /dev/null
@@ -0,0 +1,5 @@
+val activate : string -> bool -> unit
+val deactivate : string -> unit
+val clear : unit -> unit
+val iter : (bool -> string -> unit) -> unit
+val fold : (bool -> string -> 'a -> 'a) -> 'a -> 'a