summaryrefslogtreecommitdiff
path: root/system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch')
-rw-r--r--system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch141
1 files changed, 141 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch b/system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch
new file mode 100644
index 0000000000..8aae281406
--- /dev/null
+++ b/system/xen/xsa/xsa206-4.8-0014-oxenstored-don-t-wake-to-issue-no-conflict-credit.patch
@@ -0,0 +1,141 @@
+From 374c6a67e3d139a04ecde127a63ce70d24ed7b45 Mon Sep 17 00:00:00 2001
+From: Thomas Sanders <thomas.sanders@citrix.com>
+Date: Fri, 24 Mar 2017 19:55:03 +0000
+Subject: [PATCH 14/15] oxenstored: don't wake to issue no conflict-credit
+
+In the main loop, when choosing the timeout for the select function
+call, we were setting it so as to wake up to issue conflict-credit to
+any domains that could accept it. When xenstore is idle, this would
+mean waking up every 50ms (by default) to do no work. With this
+commit, we check whether any domain is below its cap, and if not then
+we set the timeout for longer (the same timeout as before the
+conflict-protection feature was added).
+
+Reported-by: Juergen Gross <jgross@suse.com>
+Signed-off-by: Thomas Sanders <thomas.sanders@citrix.com>
+Reviewed-by: Jonathan Davies <jonathan.davies@citrix.com>
+---
+ tools/ocaml/xenstored/domains.ml | 51 ++++++++++++++++++++++++++++++--------
+ tools/ocaml/xenstored/xenstored.ml | 5 +++-
+ 2 files changed, 44 insertions(+), 12 deletions(-)
+
+diff --git a/tools/ocaml/xenstored/domains.ml b/tools/ocaml/xenstored/domains.ml
+index 99f68c7..61d1e2e 100644
+--- a/tools/ocaml/xenstored/domains.ml
++++ b/tools/ocaml/xenstored/domains.ml
+@@ -35,8 +35,9 @@ type domains = {
+ on_first_conflict_pause: unit -> unit;
+
+ (* If config is set to use individual instead of aggregate conflict-rate-limiting,
+- we use this instead of the queues. *)
+- mutable n_paused: int;
++ we use these counts instead of the queues. The second one includes the first. *)
++ mutable n_paused: int; (* Number of domains with zero or negative credit *)
++ mutable n_penalised: int; (* Number of domains with less than maximum credit *)
+ }
+
+ let init eventchn on_first_conflict_pause = {
+@@ -46,6 +47,7 @@ let init eventchn on_first_conflict_pause = {
+ doms_with_conflict_penalty = Queue.create ();
+ on_first_conflict_pause = on_first_conflict_pause;
+ n_paused = 0;
++ n_penalised = 0;
+ }
+ let del doms id = Hashtbl.remove doms.table id
+ let exist doms id = Hashtbl.mem doms.table id
+@@ -53,6 +55,23 @@ let find doms id = Hashtbl.find doms.table id
+ let number doms = Hashtbl.length doms.table
+ let iter doms fct = Hashtbl.iter (fun _ b -> fct b) doms.table
+
++let rec is_empty_queue q =
++ Queue.is_empty q ||
++ if !(Queue.peek q) = None
++ then (
++ ignore (Queue.pop q);
++ is_empty_queue q
++ ) else false
++
++let all_at_max_credit doms =
++ if !Define.conflict_rate_limit_is_aggregate
++ then
++ (* Check both becuase if burst limit is 1.0 then a domain can go straight
++ * from max-credit to paused without getting into the penalty queue. *)
++ is_empty_queue doms.doms_with_conflict_penalty
++ && is_empty_queue doms.doms_conflict_paused
++ else doms.n_penalised = 0
++
+ (* Functions to handle queues of domains given that the domain might be deleted while in a queue. *)
+ let push dom queue =
+ Queue.push (ref (Some dom)) queue
+@@ -130,13 +149,16 @@ let decr_conflict_credit doms dom =
+ let before = dom.Domain.conflict_credit in
+ let after = max (-1.0) (before -. 1.0) in
+ dom.Domain.conflict_credit <- after;
++ let newly_penalised =
++ before >= !Define.conflict_burst_limit
++ && after < !Define.conflict_burst_limit in
++ let newly_paused = before > 0.0 && after <= 0.0 in
+ if !Define.conflict_rate_limit_is_aggregate then (
+- if before >= !Define.conflict_burst_limit
+- && after < !Define.conflict_burst_limit
++ if newly_penalised
+ && after > 0.0
+ then (
+ push dom doms.doms_with_conflict_penalty
+- ) else if before > 0.0 && after <= 0.0
++ ) else if newly_paused
+ then (
+ let first_pause = Queue.is_empty doms.doms_conflict_paused in
+ push dom doms.doms_conflict_paused;
+@@ -144,9 +166,12 @@ let decr_conflict_credit doms dom =
+ ) else (
+ (* The queues are correct already: no further action needed. *)
+ )
+- ) else if before > 0.0 && after <= 0.0 then (
+- doms.n_paused <- doms.n_paused + 1;
+- if doms.n_paused = 1 then doms.on_first_conflict_pause ()
++ ) else (
++ if newly_penalised then doms.n_penalised <- doms.n_penalised + 1;
++ if newly_paused then (
++ doms.n_paused <- doms.n_paused + 1;
++ if doms.n_paused = 1 then doms.on_first_conflict_pause ()
++ )
+ )
+
+ (* Give one point of credit to one domain, and update the queues appropriately. *)
+@@ -175,9 +200,13 @@ let incr_conflict_credit doms =
+ let before = dom.Domain.conflict_credit in
+ let after = min (before +. 1.0) !Define.conflict_burst_limit in
+ dom.Domain.conflict_credit <- after;
++
+ if before <= 0.0 && after > 0.0
+- then doms.n_paused <- doms.n_paused - 1
++ then doms.n_paused <- doms.n_paused - 1;
++
++ if before < !Define.conflict_burst_limit
++ && after >= !Define.conflict_burst_limit
++ then doms.n_penalised <- doms.n_penalised - 1
+ in
+- (* Scope for optimisation (probably tiny): avoid iteration if all domains are at max credit *)
+- iter doms inc
++ if doms.n_penalised > 0 then iter doms inc
+ )
+diff --git a/tools/ocaml/xenstored/xenstored.ml b/tools/ocaml/xenstored/xenstored.ml
+index d5c50fd..06387a8 100644
+--- a/tools/ocaml/xenstored/xenstored.ml
++++ b/tools/ocaml/xenstored/xenstored.ml
+@@ -437,7 +437,10 @@ let _ =
+ peaceful_mw;
+ let start_time = Unix.gettimeofday () in
+ let timeout =
+- let until_next_activity = min (max 0. (!next_frequent_ops -. start_time)) period_ops_interval in
++ let until_next_activity =
++ if Domains.all_at_max_credit domains
++ then period_ops_interval
++ else min (max 0. (!next_frequent_ops -. start_time)) period_ops_interval in
+ if peaceful_mw <> [] then 0. else until_next_activity
+ in
+ let inset, outset = Connections.select ~only_if:is_peaceful cons in
+--
+2.1.4
+