summaryrefslogtreecommitdiffhomepage
path: root/src/routingtable.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2017-04-03 05:20:25 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2017-04-04 03:44:35 +0200
commitf7d65b3268ec8f11d0fbf455ce8f7b00b0f79c47 (patch)
treee7ddc04349076e5432dd196a4472e04b8bd4811b /src/routingtable.c
parentbf71248a46a64955c53b59fe6bcbc9c35094d1c6 (diff)
locking: always use _bh
All locks are potentially between user context and softirq, which means we need to take the _bh variant. Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/routingtable.c')
-rw-r--r--src/routingtable.c48
1 files changed, 26 insertions, 22 deletions
diff --git a/src/routingtable.c b/src/routingtable.c
index 36e0bc9..1de7727 100644
--- a/src/routingtable.c
+++ b/src/routingtable.c
@@ -34,9 +34,13 @@ static inline void copy_and_assign_cidr(struct routing_table_node *node, const u
* return;
* free_node(node->bit[0]);
* free_node(node->bit[1]);
- * kfree_rcu(node);
+ * kfree_rcu_bh(node);
* }
*/
+static void node_free_rcu(struct rcu_head *rcu)
+{
+ kfree(container_of(rcu, struct routing_table_node, rcu));
+}
#define ref(p) rcu_access_pointer(p)
#define push(p) do { BUG_ON(len >= 128); stack[len++] = rcu_dereference_protected(p, lockdep_is_held(lock)); } while (0)
static void free_node(struct routing_table_node *top, struct mutex *lock)
@@ -61,7 +65,7 @@ static void free_node(struct routing_table_node *top, struct mutex *lock)
if (ref(node->bit[1]))
push(node->bit[1]);
} else {
- kfree_rcu(node, rcu);
+ call_rcu_bh(&node->rcu, node_free_rcu);
--len;
}
prev = node;
@@ -185,7 +189,7 @@ static inline struct routing_table_node *find_node(struct routing_table_node *tr
found = node;
if (node->cidr == bits)
break;
- node = rcu_dereference(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)]);
+ node = rcu_dereference_bh(node->bit[bit_at(key, node->bit_at_a, node->bit_at_b)]);
}
return found;
}
@@ -276,7 +280,7 @@ static int add(struct routing_table_node __rcu **trie, u8 bits, const u8 *key, u
}
#define push(p) do { \
- struct routing_table_node *next = (maybe_lock ? rcu_dereference_protected(p, lockdep_is_held(maybe_lock)) : rcu_dereference(p)); \
+ struct routing_table_node *next = (maybe_lock ? rcu_dereference_protected(p, lockdep_is_held(maybe_lock)) : rcu_dereference_bh(p)); \
if (next) { \
BUG_ON(len >= 128); \
stack[len++] = next; \
@@ -385,11 +389,11 @@ inline struct wireguard_peer *routing_table_lookup_v4(struct routing_table *tabl
struct wireguard_peer *peer = NULL;
struct routing_table_node *node;
- rcu_read_lock();
- node = find_node(rcu_dereference(table->root4), 32, (const u8 *)ip);
+ rcu_read_lock_bh();
+ node = find_node(rcu_dereference_bh(table->root4), 32, (const u8 *)ip);
if (node)
peer = peer_get(node->peer);
- rcu_read_unlock();
+ rcu_read_unlock_bh();
return peer;
}
@@ -399,11 +403,11 @@ inline struct wireguard_peer *routing_table_lookup_v6(struct routing_table *tabl
struct wireguard_peer *peer = NULL;
struct routing_table_node *node;
- rcu_read_lock();
- node = find_node(rcu_dereference(table->root6), 128, (const u8 *)ip);
+ rcu_read_lock_bh();
+ node = find_node(rcu_dereference_bh(table->root6), 128, (const u8 *)ip);
if (node)
peer = peer_get(node->peer);
- rcu_read_unlock();
+ rcu_read_unlock_bh();
return peer;
}
@@ -439,28 +443,28 @@ int routing_table_remove_by_peer(struct routing_table *table, struct wireguard_p
int routing_table_walk_ips(struct routing_table *table, void *ctx, int (*func)(void *ctx, struct wireguard_peer *peer, union nf_inet_addr ip, u8 cidr, int family))
{
int ret;
- rcu_read_lock();
- ret = walk_ips(rcu_dereference(table->root4), AF_INET, ctx, func, NULL);
- rcu_read_unlock();
+ rcu_read_lock_bh();
+ ret = walk_ips(rcu_dereference_bh(table->root4), AF_INET, ctx, func, NULL);
+ rcu_read_unlock_bh();
if (ret)
return ret;
- rcu_read_lock();
- ret = walk_ips(rcu_dereference(table->root6), AF_INET6, ctx, func, NULL);
- rcu_read_unlock();
+ rcu_read_lock_bh();
+ ret = walk_ips(rcu_dereference_bh(table->root6), AF_INET6, ctx, func, NULL);
+ rcu_read_unlock_bh();
return ret;
}
int routing_table_walk_ips_by_peer(struct routing_table *table, void *ctx, struct wireguard_peer *peer, int (*func)(void *ctx, union nf_inet_addr ip, u8 cidr, int family))
{
int ret;
- rcu_read_lock();
- ret = walk_ips_by_peer(rcu_dereference(table->root4), AF_INET, ctx, peer, func, NULL);
- rcu_read_unlock();
+ rcu_read_lock_bh();
+ ret = walk_ips_by_peer(rcu_dereference_bh(table->root4), AF_INET, ctx, peer, func, NULL);
+ rcu_read_unlock_bh();
if (ret)
return ret;
- rcu_read_lock();
- ret = walk_ips_by_peer(rcu_dereference(table->root6), AF_INET6, ctx, peer, func, NULL);
- rcu_read_unlock();
+ rcu_read_lock_bh();
+ ret = walk_ips_by_peer(rcu_dereference_bh(table->root6), AF_INET6, ctx, peer, func, NULL);
+ rcu_read_unlock_bh();
return ret;
}