Skip to content

Commit d28c0e4

Browse files
author
Alexei Starovoitov
committed
Merge branch 'misc-rqspinlock-updates'
Kumar Kartikeya Dwivedi says: ==================== Misc rqspinlock updates A couple of changes for rqspinlock, the first disables propagation of AA and ABBA deadlocks to waiters succeeding the deadlocking waiter. A more verbose rationale is available in the commit log. The second commit expands the stress test to introduce a ABBCCA mode that will reliably exercise the timeout fallback. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
2 parents 5913e93 + a8a0abf commit d28c0e4

File tree

3 files changed

+74
-27
lines changed

3 files changed

+74
-27
lines changed

kernel/bpf/rqspinlock.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,14 @@ int __lockfunc resilient_queued_spin_lock_slowpath(rqspinlock_t *lock, u32 val)
572572
val = res_atomic_cond_read_acquire(&lock->val, !(VAL & _Q_LOCKED_PENDING_MASK) ||
573573
RES_CHECK_TIMEOUT(ts, ret, _Q_LOCKED_PENDING_MASK));
574574

575+
/* Disable queue destruction when we detect deadlocks. */
576+
if (ret == -EDEADLK) {
577+
if (!next)
578+
next = smp_cond_load_relaxed(&node->next, (VAL));
579+
arch_mcs_spin_unlock_contended(&next->locked);
580+
goto err_release_node;
581+
}
582+
575583
waitq_timeout:
576584
if (ret) {
577585
/*

tools/testing/selftests/bpf/prog_tests/res_spin_lock.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ void serial_test_res_spin_lock_stress(void)
110110
ASSERT_OK(load_module("bpf_test_rqspinlock.ko", false), "load module AA");
111111
sleep(5);
112112
unload_module("bpf_test_rqspinlock", false);
113-
114-
ASSERT_OK(load_module_params("bpf_test_rqspinlock.ko", "test_ab=1", false), "load module ABBA");
115-
sleep(5);
116-
unload_module("bpf_test_rqspinlock", false);
113+
/*
114+
* Insert bpf_test_rqspinlock.ko manually with test_mode=[1|2] to test
115+
* other cases (ABBA, ABBCCA).
116+
*/
117117
}

tools/testing/selftests/bpf/test_kmods/bpf_test_rqspinlock.c

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,61 @@ static struct perf_event_attr hw_attr = {
2222

2323
static rqspinlock_t lock_a;
2424
static rqspinlock_t lock_b;
25+
static rqspinlock_t lock_c;
26+
27+
enum rqsl_mode {
28+
RQSL_MODE_AA = 0,
29+
RQSL_MODE_ABBA,
30+
RQSL_MODE_ABBCCA,
31+
};
32+
33+
static int test_mode = RQSL_MODE_AA;
34+
module_param(test_mode, int, 0644);
35+
MODULE_PARM_DESC(test_mode,
36+
"rqspinlock test mode: 0 = AA, 1 = ABBA, 2 = ABBCCA");
2537

2638
static struct perf_event **rqsl_evts;
2739
static int rqsl_nevts;
2840

29-
static bool test_ab = false;
30-
module_param(test_ab, bool, 0644);
31-
MODULE_PARM_DESC(test_ab, "Test ABBA situations instead of AA situations");
32-
3341
static struct task_struct **rqsl_threads;
3442
static int rqsl_nthreads;
3543
static atomic_t rqsl_ready_cpus = ATOMIC_INIT(0);
3644

3745
static int pause = 0;
3846

39-
static bool nmi_locks_a(int cpu)
47+
static const char *rqsl_mode_names[] = {
48+
[RQSL_MODE_AA] = "AA",
49+
[RQSL_MODE_ABBA] = "ABBA",
50+
[RQSL_MODE_ABBCCA] = "ABBCCA",
51+
};
52+
53+
struct rqsl_lock_pair {
54+
rqspinlock_t *worker_lock;
55+
rqspinlock_t *nmi_lock;
56+
};
57+
58+
static struct rqsl_lock_pair rqsl_get_lock_pair(int cpu)
4059
{
41-
return (cpu & 1) && test_ab;
60+
int mode = READ_ONCE(test_mode);
61+
62+
switch (mode) {
63+
default:
64+
case RQSL_MODE_AA:
65+
return (struct rqsl_lock_pair){ &lock_a, &lock_a };
66+
case RQSL_MODE_ABBA:
67+
if (cpu & 1)
68+
return (struct rqsl_lock_pair){ &lock_b, &lock_a };
69+
return (struct rqsl_lock_pair){ &lock_a, &lock_b };
70+
case RQSL_MODE_ABBCCA:
71+
switch (cpu % 3) {
72+
case 0:
73+
return (struct rqsl_lock_pair){ &lock_a, &lock_b };
74+
case 1:
75+
return (struct rqsl_lock_pair){ &lock_b, &lock_c };
76+
default:
77+
return (struct rqsl_lock_pair){ &lock_c, &lock_a };
78+
}
79+
}
4280
}
4381

4482
static int rqspinlock_worker_fn(void *arg)
@@ -51,19 +89,17 @@ static int rqspinlock_worker_fn(void *arg)
5189
atomic_inc(&rqsl_ready_cpus);
5290

5391
while (!kthread_should_stop()) {
92+
struct rqsl_lock_pair locks = rqsl_get_lock_pair(cpu);
93+
rqspinlock_t *worker_lock = locks.worker_lock;
94+
5495
if (READ_ONCE(pause)) {
5596
msleep(1000);
5697
continue;
5798
}
58-
if (nmi_locks_a(cpu))
59-
ret = raw_res_spin_lock_irqsave(&lock_b, flags);
60-
else
61-
ret = raw_res_spin_lock_irqsave(&lock_a, flags);
99+
ret = raw_res_spin_lock_irqsave(worker_lock, flags);
62100
mdelay(20);
63-
if (nmi_locks_a(cpu) && !ret)
64-
raw_res_spin_unlock_irqrestore(&lock_b, flags);
65-
else if (!ret)
66-
raw_res_spin_unlock_irqrestore(&lock_a, flags);
101+
if (!ret)
102+
raw_res_spin_unlock_irqrestore(worker_lock, flags);
67103
cpu_relax();
68104
}
69105
return 0;
@@ -91,24 +127,21 @@ static int rqspinlock_worker_fn(void *arg)
91127
static void nmi_cb(struct perf_event *event, struct perf_sample_data *data,
92128
struct pt_regs *regs)
93129
{
130+
struct rqsl_lock_pair locks;
94131
int cpu = smp_processor_id();
95132
unsigned long flags;
96133
int ret;
97134

98135
if (!cpu || READ_ONCE(pause))
99136
return;
100137

101-
if (nmi_locks_a(cpu))
102-
ret = raw_res_spin_lock_irqsave(&lock_a, flags);
103-
else
104-
ret = raw_res_spin_lock_irqsave(test_ab ? &lock_b : &lock_a, flags);
138+
locks = rqsl_get_lock_pair(cpu);
139+
ret = raw_res_spin_lock_irqsave(locks.nmi_lock, flags);
105140

106141
mdelay(10);
107142

108-
if (nmi_locks_a(cpu) && !ret)
109-
raw_res_spin_unlock_irqrestore(&lock_a, flags);
110-
else if (!ret)
111-
raw_res_spin_unlock_irqrestore(test_ab ? &lock_b : &lock_a, flags);
143+
if (!ret)
144+
raw_res_spin_unlock_irqrestore(locks.nmi_lock, flags);
112145
}
113146

114147
static void free_rqsl_threads(void)
@@ -142,13 +175,19 @@ static int bpf_test_rqspinlock_init(void)
142175
int i, ret;
143176
int ncpus = num_online_cpus();
144177

145-
pr_err("Mode = %s\n", test_ab ? "ABBA" : "AA");
178+
if (test_mode < RQSL_MODE_AA || test_mode > RQSL_MODE_ABBCCA) {
179+
pr_err("Invalid mode %d\n", test_mode);
180+
return -EINVAL;
181+
}
182+
183+
pr_err("Mode = %s\n", rqsl_mode_names[test_mode]);
146184

147185
if (ncpus < 3)
148186
return -ENOTSUPP;
149187

150188
raw_res_spin_lock_init(&lock_a);
151189
raw_res_spin_lock_init(&lock_b);
190+
raw_res_spin_lock_init(&lock_c);
152191

153192
rqsl_evts = kcalloc(ncpus - 1, sizeof(*rqsl_evts), GFP_KERNEL);
154193
if (!rqsl_evts)

0 commit comments

Comments
 (0)