Permalink
Browse files

CA-46505: add IDL for the new xapi -> storage layer and a description…

… of the per-VDI, per-datapath state machine.

This will encapsulate all the previous per-VDI refcounting etc.

Signed-off-by: David Scott <dave.scott@eu.citrix.com>
  • Loading branch information...
1 parent 79e57f6 commit 349d28deb93bc4587d896ee236469b5ca46d959a David Scott committed May 11, 2011
Showing with 271 additions and 1 deletion.
  1. +7 −1 ocaml/xapi/OMakefile
  2. +124 −0 ocaml/xapi/storage_interface.ml
  3. +140 −0 ocaml/xapi/vdi_automaton.ml
@@ -6,7 +6,8 @@ OCAMLINCLUDES = ../idl ../idl/ocaml_backend \
../xenops ../xva ../util \
../auth ../license ../client_records ../rfb ../gpg
-UseCamlp4(rpc-light.syntax, features rrd monitor_fake monitor_fake_common)
+UseCamlp4(rpc-light.syntax, features rrd monitor_fake monitor_fake_common vdi_automaton)
+UseCamlp4(rpc-light.idl, storage_interface)
CFLAGS += -std=gnu99 -Wall -Werror -I$(shell ocamlc -where)
@@ -36,6 +37,9 @@ OCamlProgram(sparse_dd, sparse_dd sparse_encoding)
OCamlProgram(show_bat, show_bat)
OCamlProgram(monitor_fake_plugin, monitor_fake_plugin monitor_fake_common rrd)
+storage_interface.mli: storage_interface.ml vdi_automaton.cmi
+ ocamlfind ocamlc -package rpc-light.idl -syntax camlp4o -i $< > $@
+
COMMON = \
xapi_templates \
../idl/api_lowlevel \
@@ -69,6 +73,8 @@ XAPI_MODULES = $(COMMON) \
storage_access \
sm_exec \
sm \
+ storage_interface \
+ vdi_automaton \
console \
xen_helpers \
importexport \
@@ -0,0 +1,124 @@
+(*
+ * Copyright (C) 2011 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *)
+(**
+ * @group Storage
+ *)
+
+open Vdi_automaton
+
+(** Primary key identifying the SR *)
+type sr = string
+
+(** Primary key identifying a VDI within an SR *)
+type vdi = string
+
+(** Opaque identifier used by the client to identify a particular operation *)
+type task = string
+
+(** The result of a successful VDI.attach: this information (eg) can be used to
+ connect a VBD backend to a VBD frontend *)
+type physical_device = string
+
+(** Each VDI is associated with one or more "attached" or "activated" "datapaths". *)
+type dp = string
+
+type success_t =
+ | Vdi of physical_device (** success (from VDI.attach) *)
+ | Unit (** success *)
+ | State of Vdi_automaton.state (** success (from VDI.stat) *)
+
+type failure_t =
+ | Sr_not_attached (** error: SR must be attached to access VDIs *)
+ | Backend_error of string * (string list) (** error: of the form SR_BACKEND_FAILURE *)
+ | Internal_error of string (** error: some unexpected internal error *)
+
+(* Represents a common "result" type. Note this is only here as a way to wrap exceptions. *)
+type result =
+ | Success of success_t
+ | Failure of failure_t
+
+let string_of_success = function
+ | Vdi x -> "VDI " ^ x
+ | Unit -> "()"
+ | State s -> Vdi_automaton.string_of_state s
+
+let string_of_failure = function
+ | Sr_not_attached -> "Sr_not_attached"
+ | Backend_error (code, params) -> Printf.sprintf "Backend_error (%s; [ %s ])" code (String.concat ";" params)
+ | Internal_error x -> "Internal_error " ^ x
+
+let string_of_result = function
+ | Success s -> "Success: " ^ (string_of_success s)
+ | Failure f -> "Failure: " ^ (string_of_failure f)
+
+let success = function
+ | Success _ -> true
+ | Failure _ -> false
+
+module DP = struct
+ (** Functions which create/destroy (or register/unregister) dps *)
+
+ (** [create task id]: creates and returns a dp *)
+ external create: task:task -> id:string -> dp = ""
+
+ (** [destroy task id]: frees any resources associated with [id] and destroys it.
+ This will typically do any needed VDI.detach, VDI.deactivate cleanup. *)
+ external destroy: task:task -> dp:dp -> allow_leak:bool -> result = ""
+
+ (** [diagnostics ()]: returns a printable set of diagnostic information,
+ typically including lists of all registered datapaths and their allocated
+ resources. *)
+ external diagnostics: unit -> string = ""
+end
+
+module SR = struct
+ (** Functions which attach/detach SRs *)
+
+ (** [attach task sr]: attaches the SR *)
+ external attach : task:task -> sr:sr -> result = ""
+
+ (** [detach task sr]: detaches the SR, first detaching and/or deactivating any
+ active VDIs. This may fail with Sr_not_attached, or any error from VDI.detach
+ or VDI.deactivate. *)
+ external detach : task:task -> sr:sr -> result = ""
+
+ (** [list task] returns the list of currently attached SRs *)
+ external list: task:task -> sr list = ""
+end
+
+module VDI = struct
+ (** Functions which operate on particular VDIs.
+ These functions are all idempotent from the point of view of a given [dp]. *)
+
+ (** [attach task dp sr vdi read_write] returns the [physical_device] for a given
+ [vdi] in [sr] which can be written to if (but not necessarily only if) [read_write]
+ is true *)
+ external attach : task:task -> dp:dp -> sr:sr -> vdi:vdi -> read_write:bool -> result = ""
+
+ (** [activate task dp sr vdi] signals the desire to immediately use [vdi].
+ This client must have called [attach] on the [vdi] first. *)
+ external activate : task:task -> dp:dp -> sr:sr -> vdi:vdi -> result = ""
+
+ (** [stat task dp sr vdi] returns the state of the given VDI from the point of view of
+ the specified dp *)
+ external stat: task:task -> dp:dp -> sr:sr -> vdi:vdi -> result = ""
+
+ (** [deactivate task dp sr vdi] signals that this client has stopped reading (and writing)
+ [vdi]. *)
+ external deactivate : task:task -> dp:dp -> sr:sr -> vdi:vdi -> result = ""
+
+ (** [detach task dp sr vdi] signals that this client no-longer needs the [physical_device]
+ to be valid. *)
+ external detach : task:task -> dp:dp -> sr:sr -> vdi:vdi -> result = ""
+end
@@ -0,0 +1,140 @@
+(*
+ * Copyright (C) 2011 Citrix Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *)
+(**
+ * @group Storage
+ *)
+
+
+(** An automaton representing the VDI state machine *)
+
+type ro_rw = RO | RW with rpc
+
+let string_of_ro_rw = function
+ | RO -> "RO" | RW -> "RW"
+
+type state =
+ | Detached
+ | Attached of ro_rw
+ | Activated of ro_rw
+with rpc
+
+let string_of_state = function
+ | Detached -> "detached"
+ | Attached ro_rw -> Printf.sprintf "attached %s" (string_of_ro_rw ro_rw)
+ | Activated ro_rw -> Printf.sprintf "activated %s" (string_of_ro_rw ro_rw)
+
+let every_state = [
+ Detached;
+ Attached RO; Attached RW;
+ Activated RO; Activated RW
+]
+
+type op =
+ | Nothing
+ | Attach of ro_rw
+ | Detach
+ | Activate
+ | Deactivate
+
+let every_op = [
+ Nothing;
+ Attach RO; Attach RW;
+ Activate;
+ Detach; Deactivate;
+]
+
+let string_of_op = function
+ | Nothing -> "nothing"
+ | Attach ro_rw -> Printf.sprintf "attach(%s)" (string_of_ro_rw ro_rw)
+ | Detach -> "detach"
+ | Activate -> Printf.sprintf "activate"
+ | Deactivate -> "deactivate"
+
+exception Bad_transition of state * op
+
+let ( + ) state operation =
+ let error () = raise (Bad_transition (state, operation)) in
+
+ let ro_rw x y = match x,y with
+ | RO, RO -> RO
+ | RW, RW -> RW
+ | RO, RW -> error ()
+ | RW, RO -> RW in
+ match state, operation with
+ | x, Nothing -> x
+ | Detached, Attach x -> Attached x
+ | Detached, Activate -> error ()
+ | Detached, Deactivate -> Detached
+ | Detached, Detach -> Detached
+ | Attached x, Attach y -> Attached (ro_rw x y)
+ | Attached x, Activate -> Activated x
+ | Attached _, Detach -> Detached
+ | Attached x, Deactivate -> Attached x
+ | Activated x, Attach y -> Activated (ro_rw x y)
+ | Activated x, Activate -> Activated x
+ | Activated x, Deactivate -> Attached x
+ | Activated _, Detach -> error ()
+
+let superstate states =
+ let activated = List.fold_left (fun acc s ->
+ acc || (s = Activated RO) || (s = Activated RW)) false states in
+ let rw = List.fold_left (fun acc s ->
+ acc || (s = Activated RW) || (s = Attached RW)) false states in
+ if states = []
+ then Detached
+ else
+ if activated
+ then Activated (if rw then RW else RO)
+ else Attached (if rw then RW else RO)
+
+exception No_operation of state * state
+
+(* x - y = [ (op, state_on_fail)+ ] *)
+let ( - ) x y = match x, y with
+ | Detached, Detached -> [ Nothing, Detached ]
+ | Attached RO, Attached RO -> [ Nothing, Attached RO ]
+ | Activated RO, Activated RO -> [ Nothing, Activated RO ]
+ | Attached RW, Attached RW -> [ Nothing, Attached RW ]
+ | Activated RW, Activated RW -> [ Nothing, Activated RW ]
+ | Attached r, Detached -> [ Detach, Attached r ]
+ | Activated RO, Attached RO -> [ Deactivate, Activated RO ]
+ | Activated RW, Attached RW -> [ Deactivate, Activated RW ]
+ | Activated r, Detached -> [ Deactivate, Activated r; Detach, Attached r ]
+ | Detached, Attached RO -> [ Attach RO, Detached ]
+ | Detached, Attached RW -> [ Attach RW, Detached ]
+ | Detached, Activated RO -> [ Attach RO, Detached; Activate, Attached RO ]
+ | Detached, Activated RW -> [ Attach RW, Detached; Activate, Attached RW ]
+ | Attached RO, Activated RO -> [ Activate, Attached RO ]
+ | Attached RW, Activated RW -> [ Activate, Attached RW ]
+ | _, _ -> raise (No_operation (x, y))
+
+(* For any state [s] and operation [o] where [s' = s + o],
+ [if s <> s' then s - s' = op] *)
+
+let all_pairs x y =
+ List.fold_left (fun acc x -> List.map (fun y -> x, y) y @ acc) [] x
+
+let test () =
+ List.iter
+ (fun (s, op) ->
+ try
+ let s' = s + op in
+ let op' = List.map fst (s - s') in
+ if s <> s' && [ op ] <> op'
+ then failwith (Printf.sprintf "s = %s; op = %s; s + op = %s; s - (s + op) = %s"
+ (string_of_state s) (string_of_op op)
+ (string_of_state s')
+ (String.concat ", " (List.map string_of_op op')))
+ with Bad_transition(_, _) -> ()
+ ) (all_pairs every_state every_op)

0 comments on commit 349d28d

Please sign in to comment.