aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/peer.c
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2016-11-02 14:26:28 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2016-11-03 14:01:01 +0100
commitc8b111bad16160aec5cf944bcf6fb1da47d601db (patch)
tree815b8ac6c458b7f2ee856378c6cf3f3a62fe0d68 /src/peer.c
parenttools: abstract pkg-config to PKG_CONFIG (diff)
downloadwireguard-monolithic-historical-c8b111bad16160aec5cf944bcf6fb1da47d601db.tar.xz
wireguard-monolithic-historical-c8b111bad16160aec5cf944bcf6fb1da47d601db.zip
timers: take reference like a lookup table
Diffstat (limited to 'src/peer.c')
-rw-r--r--src/peer.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/peer.c b/src/peer.c
index aa630a4..e1aaf6b 100644
--- a/src/peer.c
+++ b/src/peer.c
@@ -49,15 +49,26 @@ struct wireguard_peer *peer_get(struct wireguard_peer *peer)
return peer;
}
+struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer)
+{
+ rcu_read_lock();
+ peer = peer_get(peer);
+ rcu_read_unlock();
+ return peer;
+}
+
+/* We have a separate "remove" function to get rid of the final reference because
+ * peer_list, clearing handshakes, and flushing all require mutexes which requires
+ * sleeping, which must only be done from certain contexts. */
void peer_remove(struct wireguard_peer *peer)
{
if (unlikely(!peer))
return;
lockdep_assert_held(&peer->device->device_update_lock);
-
- list_del(&peer->peer_list);
noise_handshake_clear(&peer->handshake);
noise_keypairs_clear(&peer->keypairs);
+ list_del(&peer->peer_list);
+ timers_uninit_peer(peer);
routing_table_remove_by_peer(&peer->device->peer_routing_table, peer);
pubkey_hashtable_remove(&peer->device->peer_hashtable, peer);
if (peer->device->workqueue)
@@ -70,12 +81,10 @@ static void rcu_release(struct rcu_head *rcu)
{
struct wireguard_peer *peer = container_of(rcu, struct wireguard_peer, rcu);
pr_debug("Peer %Lu (%pISpfsc) destroyed\n", peer->internal_id, &peer->endpoint_addr);
- timers_uninit_peer(peer);
skb_queue_purge(&peer->tx_packet_queue);
if (peer->endpoint_dst)
dst_release(peer->endpoint_dst);
- memzero_explicit(peer, sizeof(struct wireguard_peer));
- kfree(peer);
+ kzfree(peer);
}
static void kref_release(struct kref *refcount)
@@ -98,9 +107,7 @@ int peer_for_each_unlocked(struct wireguard_device *wg, int (*fn)(struct wiregua
lockdep_assert_held(&wg->device_update_lock);
list_for_each_entry_safe(peer, temp, &wg->peer_list, peer_list) {
- rcu_read_lock();
- peer = peer_get(peer);
- rcu_read_unlock();
+ peer = peer_rcu_get(peer);
if (unlikely(!peer))
continue;
ret = fn(peer, data);