For now, raw_spinlock is used during adding, deleting and updating in the
bpf lru map, which can lead to deadlock if it is done in the NMI context,
as described in [1].

Fix this by convert the raw_spinlock_t in bpf_lru_list and
bpf_lru_locallist to rqspinlock_t.

Link: 
https://lore.kernel.org/bpf/CAEf4BzbTJCUx0D=zjx6+5m5iighwlzap94hnw36zmdhaf4-...@mail.gmail.com/
Signed-off-by: Menglong Dong <[email protected]>
---
 kernel/bpf/bpf_lru_list.c | 47 +++++++++++++++++++++++----------------
 kernel/bpf/bpf_lru_list.h |  5 +++--
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/kernel/bpf/bpf_lru_list.c b/kernel/bpf/bpf_lru_list.c
index e7a2fc60523f..38fddcb1e28c 100644
--- a/kernel/bpf/bpf_lru_list.c
+++ b/kernel/bpf/bpf_lru_list.c
@@ -307,9 +307,10 @@ static void bpf_lru_list_push_free(struct bpf_lru_list *l,
        if (WARN_ON_ONCE(IS_LOCAL_LIST_TYPE(node->type)))
                return;
 
-       raw_spin_lock_irqsave(&l->lock, flags);
+       if (raw_res_spin_lock_irqsave(&l->lock, flags))
+               return;
        __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE);
-       raw_spin_unlock_irqrestore(&l->lock, flags);
+       raw_res_spin_unlock_irqrestore(&l->lock, flags);
 }
 
 static void bpf_lru_list_pop_free_to_local(struct bpf_lru *lru,
@@ -319,7 +320,8 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru 
*lru,
        struct bpf_lru_node *node, *tmp_node;
        unsigned int nfree = 0;
 
-       raw_spin_lock(&l->lock);
+       if (raw_res_spin_lock(&l->lock))
+               return;
 
        __local_list_flush(l, loc_l);
 
@@ -338,7 +340,7 @@ static void bpf_lru_list_pop_free_to_local(struct bpf_lru 
*lru,
                                      local_free_list(loc_l),
                                      BPF_LRU_LOCAL_LIST_T_FREE);
 
-       raw_spin_unlock(&l->lock);
+       raw_res_spin_unlock(&l->lock);
 }
 
 static void __local_list_add_pending(struct bpf_lru *lru,
@@ -404,7 +406,8 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(struct 
bpf_lru *lru,
 
        l = per_cpu_ptr(lru->percpu_lru, cpu);
 
-       raw_spin_lock_irqsave(&l->lock, flags);
+       if (raw_res_spin_lock_irqsave(&l->lock, flags))
+               return NULL;
 
        __bpf_lru_list_rotate(lru, l);
 
@@ -420,7 +423,7 @@ static struct bpf_lru_node *bpf_percpu_lru_pop_free(struct 
bpf_lru *lru,
                __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_INACTIVE);
        }
 
-       raw_spin_unlock_irqrestore(&l->lock, flags);
+       raw_res_spin_unlock_irqrestore(&l->lock, flags);
 
        return node;
 }
@@ -437,7 +440,8 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct 
bpf_lru *lru,
 
        loc_l = per_cpu_ptr(clru->local_list, cpu);
 
-       raw_spin_lock_irqsave(&loc_l->lock, flags);
+       if (raw_res_spin_lock_irqsave(&loc_l->lock, flags))
+               return NULL;
 
        node = __local_list_pop_free(loc_l);
        if (!node) {
@@ -448,7 +452,7 @@ static struct bpf_lru_node *bpf_common_lru_pop_free(struct 
bpf_lru *lru,
        if (node)
                __local_list_add_pending(lru, loc_l, cpu, node, hash);
 
-       raw_spin_unlock_irqrestore(&loc_l->lock, flags);
+       raw_res_spin_unlock_irqrestore(&loc_l->lock, flags);
 
        if (node)
                return node;
@@ -466,23 +470,26 @@ static struct bpf_lru_node 
*bpf_common_lru_pop_free(struct bpf_lru *lru,
        do {
                steal_loc_l = per_cpu_ptr(clru->local_list, steal);
 
-               raw_spin_lock_irqsave(&steal_loc_l->lock, flags);
+               if (raw_res_spin_lock_irqsave(&steal_loc_l->lock, flags))
+                       goto out_next;
 
                node = __local_list_pop_free(steal_loc_l);
                if (!node)
                        node = __local_list_pop_pending(lru, steal_loc_l);
 
-               raw_spin_unlock_irqrestore(&steal_loc_l->lock, flags);
+               raw_res_spin_unlock_irqrestore(&steal_loc_l->lock, flags);
 
+out_next:
                steal = cpumask_next_wrap(steal, cpu_possible_mask);
        } while (!node && steal != first_steal);
 
        loc_l->next_steal = steal;
 
        if (node) {
-               raw_spin_lock_irqsave(&loc_l->lock, flags);
+               if (raw_res_spin_lock_irqsave(&loc_l->lock, flags))
+                       return NULL;
                __local_list_add_pending(lru, loc_l, cpu, node, hash);
-               raw_spin_unlock_irqrestore(&loc_l->lock, flags);
+               raw_res_spin_unlock_irqrestore(&loc_l->lock, flags);
        }
 
        return node;
@@ -511,10 +518,11 @@ static void bpf_common_lru_push_free(struct bpf_lru *lru,
 
                loc_l = per_cpu_ptr(lru->common_lru.local_list, node->cpu);
 
-               raw_spin_lock_irqsave(&loc_l->lock, flags);
+               if (raw_res_spin_lock_irqsave(&loc_l->lock, flags))
+                       return;
 
                if (unlikely(node->type != BPF_LRU_LOCAL_LIST_T_PENDING)) {
-                       raw_spin_unlock_irqrestore(&loc_l->lock, flags);
+                       raw_res_spin_unlock_irqrestore(&loc_l->lock, flags);
                        goto check_lru_list;
                }
 
@@ -522,7 +530,7 @@ static void bpf_common_lru_push_free(struct bpf_lru *lru,
                bpf_lru_node_clear_ref(node);
                list_move(&node->list, local_free_list(loc_l));
 
-               raw_spin_unlock_irqrestore(&loc_l->lock, flags);
+               raw_res_spin_unlock_irqrestore(&loc_l->lock, flags);
                return;
        }
 
@@ -538,11 +546,12 @@ static void bpf_percpu_lru_push_free(struct bpf_lru *lru,
 
        l = per_cpu_ptr(lru->percpu_lru, node->cpu);
 
-       raw_spin_lock_irqsave(&l->lock, flags);
+       if (raw_res_spin_lock_irqsave(&l->lock, flags))
+               return;
 
        __bpf_lru_node_move(l, node, BPF_LRU_LIST_T_FREE);
 
-       raw_spin_unlock_irqrestore(&l->lock, flags);
+       raw_res_spin_unlock_irqrestore(&l->lock, flags);
 }
 
 void bpf_lru_push_free(struct bpf_lru *lru, struct bpf_lru_node *node)
@@ -625,7 +634,7 @@ static void bpf_lru_locallist_init(struct bpf_lru_locallist 
*loc_l, int cpu)
 
        loc_l->next_steal = cpu;
 
-       raw_spin_lock_init(&loc_l->lock);
+       raw_res_spin_lock_init(&loc_l->lock);
 }
 
 static void bpf_lru_list_init(struct bpf_lru_list *l)
@@ -640,7 +649,7 @@ static void bpf_lru_list_init(struct bpf_lru_list *l)
 
        l->next_inactive_rotation = &l->lists[BPF_LRU_LIST_T_INACTIVE];
 
-       raw_spin_lock_init(&l->lock);
+       raw_res_spin_lock_init(&l->lock);
 }
 
 int bpf_lru_init(struct bpf_lru *lru, bool percpu, u32 hash_offset,
diff --git a/kernel/bpf/bpf_lru_list.h b/kernel/bpf/bpf_lru_list.h
index fe2661a58ea9..61fc7d7f9de1 100644
--- a/kernel/bpf/bpf_lru_list.h
+++ b/kernel/bpf/bpf_lru_list.h
@@ -7,6 +7,7 @@
 #include <linux/cache.h>
 #include <linux/list.h>
 #include <linux/spinlock_types.h>
+#include <asm-generic/rqspinlock.h>
 
 #define NR_BPF_LRU_LIST_T      (3)
 #define NR_BPF_LRU_LIST_COUNT  (2)
@@ -34,13 +35,13 @@ struct bpf_lru_list {
        /* The next inactive list rotation starts from here */
        struct list_head *next_inactive_rotation;
 
-       raw_spinlock_t lock ____cacheline_aligned_in_smp;
+       rqspinlock_t lock ____cacheline_aligned_in_smp;
 };
 
 struct bpf_lru_locallist {
        struct list_head lists[NR_BPF_LRU_LOCAL_LIST_T];
        u16 next_steal;
-       raw_spinlock_t lock;
+       rqspinlock_t lock;
 };
 
 struct bpf_common_lru {
-- 
2.51.2


Reply via email to