mirror of
https://github.com/linuxkit/linuxkit.git
synced 2025-11-13 06:10:02 +00:00
83 lines
3.0 KiB
Diff
83 lines
3.0 KiB
Diff
From: Thomas Gleixner <tglx@linutronix.de>
|
|
Date: Mon, 24 Feb 2020 15:01:34 +0100
|
|
Subject: [PATCH 03/22] bpf: Update locking comment in hashtab code
|
|
|
|
The comment where the bucket lock is acquired says:
|
|
|
|
/* bpf_map_update_elem() can be called in_irq() */
|
|
|
|
which is not really helpful and aside of that it does not explain the
|
|
subtle details of the hash bucket locks expecially in the context of BPF
|
|
and perf, kprobes and tracing.
|
|
|
|
Add a comment at the top of the file which explains the protection scopes
|
|
and the details how potential deadlocks are prevented.
|
|
|
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
|
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
|
|
---
|
|
kernel/bpf/hashtab.c | 24 ++++++++++++++++++++----
|
|
1 file changed, 20 insertions(+), 4 deletions(-)
|
|
|
|
--- a/kernel/bpf/hashtab.c
|
|
+++ b/kernel/bpf/hashtab.c
|
|
@@ -17,6 +17,26 @@
|
|
(BPF_F_NO_PREALLOC | BPF_F_NO_COMMON_LRU | BPF_F_NUMA_NODE | \
|
|
BPF_F_ACCESS_MASK | BPF_F_ZERO_SEED)
|
|
|
|
+/*
|
|
+ * The bucket lock has two protection scopes:
|
|
+ *
|
|
+ * 1) Serializing concurrent operations from BPF programs on differrent
|
|
+ * CPUs
|
|
+ *
|
|
+ * 2) Serializing concurrent operations from BPF programs and sys_bpf()
|
|
+ *
|
|
+ * BPF programs can execute in any context including perf, kprobes and
|
|
+ * tracing. As there are almost no limits where perf, kprobes and tracing
|
|
+ * can be invoked from the lock operations need to be protected against
|
|
+ * deadlocks. Deadlocks can be caused by recursion and by an invocation in
|
|
+ * the lock held section when functions which acquire this lock are invoked
|
|
+ * from sys_bpf(). BPF recursion is prevented by incrementing the per CPU
|
|
+ * variable bpf_prog_active, which prevents BPF programs attached to perf
|
|
+ * events, kprobes and tracing to be invoked before the prior invocation
|
|
+ * from one of these contexts completed. sys_bpf() uses the same mechanism
|
|
+ * by pinning the task to the current CPU and incrementing the recursion
|
|
+ * protection accross the map operation.
|
|
+ */
|
|
struct bucket {
|
|
struct hlist_nulls_head head;
|
|
raw_spinlock_t lock;
|
|
@@ -862,7 +882,6 @@ static int htab_map_update_elem(struct b
|
|
*/
|
|
}
|
|
|
|
- /* bpf_map_update_elem() can be called in_irq() */
|
|
raw_spin_lock_irqsave(&b->lock, flags);
|
|
|
|
l_old = lookup_elem_raw(head, hash, key, key_size);
|
|
@@ -942,7 +961,6 @@ static int htab_lru_map_update_elem(stru
|
|
return -ENOMEM;
|
|
memcpy(l_new->key + round_up(map->key_size, 8), value, map->value_size);
|
|
|
|
- /* bpf_map_update_elem() can be called in_irq() */
|
|
raw_spin_lock_irqsave(&b->lock, flags);
|
|
|
|
l_old = lookup_elem_raw(head, hash, key, key_size);
|
|
@@ -997,7 +1015,6 @@ static int __htab_percpu_map_update_elem
|
|
b = __select_bucket(htab, hash);
|
|
head = &b->head;
|
|
|
|
- /* bpf_map_update_elem() can be called in_irq() */
|
|
raw_spin_lock_irqsave(&b->lock, flags);
|
|
|
|
l_old = lookup_elem_raw(head, hash, key, key_size);
|
|
@@ -1061,7 +1078,6 @@ static int __htab_lru_percpu_map_update_
|
|
return -ENOMEM;
|
|
}
|
|
|
|
- /* bpf_map_update_elem() can be called in_irq() */
|
|
raw_spin_lock_irqsave(&b->lock, flags);
|
|
|
|
l_old = lookup_elem_raw(head, hash, key, key_size);
|