]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
bpf: Convert lpm_trie.c to rqspinlock
authorKumar Kartikeya Dwivedi <memxor@gmail.com>
Sun, 16 Mar 2025 04:05:37 +0000 (21:05 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Wed, 19 Mar 2025 15:03:05 +0000 (08:03 -0700)
Convert all LPM trie usage of raw_spinlock to rqspinlock.

Note that rcu_dereference_protected in trie_delete_elem is switched over
to plain rcu_dereference, the RCU read lock should be held from BPF
program side or eBPF syscall path, and the trie->lock is just acquired
before the dereference. It is not clear the reason the protected variant
was used from the commit history, but the above reasoning makes sense so
switch over.

Closes: https://lore.kernel.org/lkml/000000000000adb08b061413919e@google.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
Link: https://lore.kernel.org/r/20250316040541.108729-22-memxor@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
kernel/bpf/lpm_trie.c

index e8a772e6432425062a67195ed91d5fa498209ddc..be66d7e520e0d3d48eb14b4f444b265bb2d2a85f 100644 (file)
@@ -15,6 +15,7 @@
 #include <net/ipv6.h>
 #include <uapi/linux/btf.h>
 #include <linux/btf_ids.h>
+#include <asm/rqspinlock.h>
 #include <linux/bpf_mem_alloc.h>
 
 /* Intermediate node */
@@ -36,7 +37,7 @@ struct lpm_trie {
        size_t                          n_entries;
        size_t                          max_prefixlen;
        size_t                          data_size;
-       raw_spinlock_t                  lock;
+       rqspinlock_t                    lock;
 };
 
 /* This trie implements a longest prefix match algorithm that can be used to
@@ -342,7 +343,9 @@ static long trie_update_elem(struct bpf_map *map,
        if (!new_node)
                return -ENOMEM;
 
-       raw_spin_lock_irqsave(&trie->lock, irq_flags);
+       ret = raw_res_spin_lock_irqsave(&trie->lock, irq_flags);
+       if (ret)
+               goto out_free;
 
        new_node->prefixlen = key->prefixlen;
        RCU_INIT_POINTER(new_node->child[0], NULL);
@@ -356,8 +359,7 @@ static long trie_update_elem(struct bpf_map *map,
         */
        slot = &trie->root;
 
-       while ((node = rcu_dereference_protected(*slot,
-                                       lockdep_is_held(&trie->lock)))) {
+       while ((node = rcu_dereference(*slot))) {
                matchlen = longest_prefix_match(trie, node, key);
 
                if (node->prefixlen != matchlen ||
@@ -442,8 +444,8 @@ static long trie_update_elem(struct bpf_map *map,
        rcu_assign_pointer(*slot, im_node);
 
 out:
-       raw_spin_unlock_irqrestore(&trie->lock, irq_flags);
-
+       raw_res_spin_unlock_irqrestore(&trie->lock, irq_flags);
+out_free:
        if (ret)
                bpf_mem_cache_free(&trie->ma, new_node);
        bpf_mem_cache_free_rcu(&trie->ma, free_node);
@@ -467,7 +469,9 @@ static long trie_delete_elem(struct bpf_map *map, void *_key)
        if (key->prefixlen > trie->max_prefixlen)
                return -EINVAL;
 
-       raw_spin_lock_irqsave(&trie->lock, irq_flags);
+       ret = raw_res_spin_lock_irqsave(&trie->lock, irq_flags);
+       if (ret)
+               return ret;
 
        /* Walk the tree looking for an exact key/length match and keeping
         * track of the path we traverse.  We will need to know the node
@@ -478,8 +482,7 @@ static long trie_delete_elem(struct bpf_map *map, void *_key)
        trim = &trie->root;
        trim2 = trim;
        parent = NULL;
-       while ((node = rcu_dereference_protected(
-                      *trim, lockdep_is_held(&trie->lock)))) {
+       while ((node = rcu_dereference(*trim))) {
                matchlen = longest_prefix_match(trie, node, key);
 
                if (node->prefixlen != matchlen ||
@@ -543,7 +546,7 @@ static long trie_delete_elem(struct bpf_map *map, void *_key)
        free_node = node;
 
 out:
-       raw_spin_unlock_irqrestore(&trie->lock, irq_flags);
+       raw_res_spin_unlock_irqrestore(&trie->lock, irq_flags);
 
        bpf_mem_cache_free_rcu(&trie->ma, free_parent);
        bpf_mem_cache_free_rcu(&trie->ma, free_node);
@@ -592,7 +595,7 @@ static struct bpf_map *trie_alloc(union bpf_attr *attr)
                          offsetof(struct bpf_lpm_trie_key_u8, data);
        trie->max_prefixlen = trie->data_size * 8;
 
-       raw_spin_lock_init(&trie->lock);
+       raw_res_spin_lock_init(&trie->lock);
 
        /* Allocate intermediate and leaf nodes from the same allocator */
        leaf_size = sizeof(struct lpm_trie_node) + trie->data_size +