summaryrefslogtreecommitdiffhomepage
path: root/src/allowedips.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-08-01 05:45:49 +0200
committerJason A. Donenfeld <Jason@zx2c4.com>2018-08-01 06:42:35 +0200
commit2ed11903fb8e9330f16699026e5b4f2ff156f803 (patch)
tree9b7ca73d2ef5fde8a28e17f478a414913beb24c6 /src/allowedips.c
parent8918d2950dec300b35fa470afbf089d8f3f0a906 (diff)
allowedips: free root inside of RCU callback
This reduces the amount of call_rcu invocations considerably. Suggested-by: Stephen Hemminger <stephen@networkplumber.org> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
Diffstat (limited to 'src/allowedips.c')
-rw-r--r--src/allowedips.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/src/allowedips.c b/src/allowedips.c
index 634cfb6..7106f41 100644
--- a/src/allowedips.c
+++ b/src/allowedips.c
@@ -49,17 +49,17 @@ static void node_free_rcu(struct rcu_head *rcu)
#define push(stack, p, len) ({ \
if (rcu_access_pointer(p)) { \
BUG_ON(len >= 128); \
- stack[len++] = rcu_dereference_protected(p, lockdep_is_held(lock)); \
+ stack[len++] = rcu_dereference_raw(p); \
} \
true; \
})
-static void free_root_node(struct allowedips_node __rcu *top, struct mutex *lock)
+static void root_free_rcu(struct rcu_head *rcu)
{
- struct allowedips_node *stack[128], *node;
- unsigned int len;
+ struct allowedips_node *node, *stack[128] = { container_of(rcu, struct allowedips_node, rcu) };
+ unsigned int len = 1;
- for (len = 0, push(stack, top, len); len > 0 && (node = stack[--len]) && push(stack, node->bit[0], len) && push(stack, node->bit[1], len);)
- call_rcu_bh(&node->rcu, node_free_rcu);
+ while (len > 0 && (node = stack[--len]) && push(stack, node->bit[0], len) && push(stack, node->bit[1], len))
+ kfree(node);
}
static int walk_by_peer(struct allowedips_node __rcu *top, u8 bits, struct allowedips_cursor *cursor, struct wireguard_peer *peer, int (*func)(void *ctx, const u8 *ip, u8 cidr, int family), void *ctx, struct mutex *lock)
@@ -287,8 +287,10 @@ void allowedips_free(struct allowedips *table, struct mutex *lock)
++table->seq;
RCU_INIT_POINTER(table->root4, NULL);
RCU_INIT_POINTER(table->root6, NULL);
- free_root_node(old4, lock);
- free_root_node(old6, lock);
+ if (rcu_access_pointer(old4))
+ call_rcu_bh(&rcu_dereference_protected(old4, lockdep_is_held(lock))->rcu, root_free_rcu);
+ if (rcu_access_pointer(old6))
+ call_rcu_bh(&rcu_dereference_protected(old6, lockdep_is_held(lock))->rcu, root_free_rcu);
}
int allowedips_insert_v4(struct allowedips *table, const struct in_addr *ip, u8 cidr, struct wireguard_peer *peer, struct mutex *lock)