]> xenbits.xensource.com Git - xen.git/commitdiff
oxenstored: perform a 3-way merge of the quota after a transaction
authorJerome Maloberti <jerome.maloberti@citrix.com>
Fri, 24 Mar 2017 16:57:40 +0000 (16:57 +0000)
committerIan Jackson <Ian.Jackson@eu.citrix.com>
Wed, 5 Apr 2017 14:26:37 +0000 (15:26 +0100)
At a beginning of a transaction, the quotas from the global store
are duplicated and modified by the transaction. If during the
transaction, an action associated to no transaction is concurrently
executed, the quotas of the global store are updated, and then the
updates are lost when the transaction merges.

We fix this problem by keeping another copy of the quota at the
beginning of the transaction, and performing a 3-way merge between
the quotas from the transaction and the "original" copy of the quota
onto the quota of the global store.

Reported-by: Juergen Gross <jgross@suse.com>
Signed-off-by: Jerome Maloberti <jerome.maloberti@citrix.com>
Signed-off-by: Euan Harris <euan.harris@citrix.com>
Acked-by: David Scott <dave.scott@citrix.com>
tools/ocaml/xenstored/quota.ml
tools/ocaml/xenstored/store.ml
tools/ocaml/xenstored/transaction.ml

index c668302432595be057aa0b9435276151f9ca4e37..e6953c63f1126b6b9fd59d5c2722695beaf0960f 100644 (file)
@@ -81,3 +81,8 @@ let add_entry quota id =
 
 let add quota diff =
        Hashtbl.iter (fun id nb -> set_entry quota id (get_entry quota id + nb)) diff.cur
+
+let merge orig_quota mod_quota dest_quota =
+         Hashtbl.iter (fun id nb -> let diff = nb - (get_entry orig_quota id) in
+                               if diff <> 0 then
+                                       set_entry dest_quota id ((get_entry dest_quota id) + diff)) mod_quota.cur
index 3efe515dcc2a8843eb4024299d3a6f9d94e039ed..223ee21ebb89e915e77bdad1aef83a997c3b563d 100644 (file)
@@ -188,20 +188,17 @@ let rec get_deepest_existing_node node = function
                with Not_found -> node, false
 
 let set_node rnode path nnode =
-       let quota = Quota.create () in
-       if !Quota.activate then Node.recurse (fun node -> Quota.add_entry quota (Node.get_owner node)) nnode;
        if path = [] then
-               nnode, quota
+               nnode
        else
                let set_node node name =
                        try
                                let ent = Node.find node name in
-                               if !Quota.activate then Node.recurse (fun node -> Quota.del_entry quota (Node.get_owner node)) ent;
                                Node.replace_child node ent nnode
                        with Not_found ->
                                Node.add_child node nnode
                        in
-               apply_modify rnode path set_node, quota
+               apply_modify rnode path set_node
 
 (* read | ls | getperms use this *)
 let rec lookup node path fct =
@@ -375,10 +372,10 @@ let dump_buffer store = dump_store_buf store.root
 
 
 (* modifying functions with quota udpate *)
-let set_node store path node =
-       let root, quota_diff = Path.set_node store.root path node in
+let set_node store path node orig_quota mod_quota =
+       let root = Path.set_node store.root path node in
        store.root <- root;
-       Quota.add store.quota quota_diff
+       Quota.merge orig_quota mod_quota store.quota
 
 let write store perm path value =
        let node, existing = get_deepest_existing_node store path in
index e59d6814bf9394d211e3c1213c390fc3dd4efcf1..77de4e8ac1726ac210cacf24201c2fe8df1ba064 100644 (file)
@@ -74,6 +74,7 @@ type ty = No | Full of (int * Store.Node.t * Store.t)
 type t = {
        ty: ty;
        store: Store.t;
+       quota: Quota.t;
        mutable ops: (Xenbus.Xb.Op.operation * Store.Path.t) list;
        mutable read_lowpath: Store.Path.t option;
        mutable write_lowpath: Store.Path.t option;
@@ -84,6 +85,7 @@ let make id store =
        {
                ty = ty;
                store = if id = none then store else Store.copy store;
+               quota = Quota.copy store.Store.quota;
                ops = [];
                read_lowpath = None;
                write_lowpath = None;
@@ -155,7 +157,7 @@ let commit ~con t =
 
                                        (* it has to be in the store, otherwise it means bugs
                                           in the lowpath registration. we don't need to handle none. *)
-                                       maybe (fun n -> Store.set_node cstore p n) n;
+                                       maybe (fun n -> Store.set_node cstore p n t.quota store.Store.quota) n;
                                        Logging.write_coalesce ~tid:(get_id t) ~con (Store.Path.to_string p);
                                ) t.write_lowpath;
                                maybe (fun p ->