-
Notifications
You must be signed in to change notification settings - Fork 3
/
0019-locking-qspinlock-Introduce-starvation-avoidance-int.patch
88 lines (78 loc) · 2.83 KB
/
0019-locking-qspinlock-Introduce-starvation-avoidance-int.patch
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
From b0ea2191da927217943679b82f8be2eb049a1800 Mon Sep 17 00:00:00 2001
From: AltArch Kernel <[email protected]>
Date: Wed, 23 Sep 2020 16:54:29 +0800
Subject: [PATCH 19/25] locking/qspinlock: Introduce starvation avoidance into
CNA
hulk inclusion
category: feature
bugzilla: 13227
CVE: NA
-------------------------------------------------
Choose the next lock holder among spinning threads running on the same
node with high probability rather than always. With small probability,
hand the lock to the first thread in the secondary queue or, if that
queue is empty, to the immediate successor of the current lock holder
in the main queue. Thus, assuming no failures while threads hold the
lock, every thread would be able to acquire the lock after a bounded
number of lock transitions, with high probability.
---
kernel/locking/qspinlock_cna.h | 35 +++++++++++++++++++++++++++++++++--
1 file changed, 33 insertions(+), 2 deletions(-)
diff --git a/kernel/locking/qspinlock_cna.h b/kernel/locking/qspinlock_cna.h
index 8c56bbf..08748a5 100644
--- a/kernel/locking/qspinlock_cna.h
+++ b/kernel/locking/qspinlock_cna.h
@@ -4,6 +4,7 @@
#endif
#include <linux/topology.h>
+#include <linux/random.h>
/*
* Implement a NUMA-aware version of MCS (aka CNA, or compact NUMA-aware lock).
@@ -50,6 +51,34 @@ struct cna_node {
struct cna_node *tail; /* points to the secondary queue tail */
};
+/* Per-CPU pseudo-random number seed */
+static DEFINE_PER_CPU(u32, seed);
+
+/*
+ * Controls the probability for intra-node lock hand-off. It can be
+ * tuned and depend, e.g., on the number of CPUs per node. For now,
+ * choose a value that provides reasonable long-term fairness without
+ * sacrificing performance compared to a version that does not have any
+ * fairness guarantees.
+ */
+#define INTRA_NODE_HANDOFF_PROB_ARG (16)
+
+/*
+ * Return false with probability 1 / 2^@num_bits.
+ * Intuitively, the larger @num_bits the less likely false is to be returned.
+ * @num_bits must be a number between 0 and 31.
+ */
+static bool probably(unsigned int num_bits)
+{
+ u32 s;
+
+ s = this_cpu_read(seed);
+ s = next_pseudo_random32(s);
+ this_cpu_write(seed, s);
+
+ return s & ((1 << num_bits) - 1);
+}
+
static void __init cna_init_nodes_per_cpu(unsigned int cpu)
{
struct mcs_spinlock *base = per_cpu_ptr(&qnodes[0].mcs, cpu);
@@ -202,9 +231,11 @@ static inline void cna_pass_lock(struct mcs_spinlock *node,
/*
* Try to find a successor running on the same NUMA node
- * as the current lock holder.
+ * as the current lock holder. For long-term fairness,
+ * search for such a thread with high probability rather than always.
*/
- new_next = cna_try_find_next(node, next);
+ if (probably(INTRA_NODE_HANDOFF_PROB_ARG))
+ new_next = cna_try_find_next(node, next);
if (new_next) { /* if such successor is found */
next_holder = new_next;
--
1.8.3.1