Skip to content
This repository was archived by the owner on Dec 27, 2019. It is now read-only.

Commit b713ab0

Browse files
committed
peer: simplify rcu reference counts
Use RCU reference counts only when we must, and otherwise use a more reasonably named function. Reported-by: Jann Horn <jann@thejh.net>
1 parent 153c9f6 commit b713ab0

9 files changed

Lines changed: 23 additions & 30 deletions

File tree

src/allowedips.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ static __always_inline struct wireguard_peer *lookup(struct allowedips_node __rc
182182
rcu_read_lock_bh();
183183
node = find_node(rcu_dereference_bh(root), bits, ip);
184184
if (node)
185-
peer = peer_get(node->peer);
185+
peer = peer_get_maybe_zero(node->peer);
186186
rcu_read_unlock_bh();
187187
return peer;
188188
}

src/hashtables.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ struct wireguard_peer *pubkey_hashtable_lookup(struct pubkey_hashtable *table, c
4848
break;
4949
}
5050
}
51-
peer = peer_get(peer);
51+
peer = peer_get_maybe_zero(peer);
5252
rcu_read_unlock_bh();
5353
return peer;
5454
}
@@ -159,7 +159,7 @@ struct index_hashtable_entry *index_hashtable_lookup(struct index_hashtable *tab
159159
}
160160
}
161161
if (likely(entry)) {
162-
entry->peer = peer_get(entry->peer);
162+
entry->peer = peer_get_maybe_zero(entry->peer);
163163
if (unlikely(!entry->peer))
164164
entry = NULL;
165165
}

src/netlink.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,8 @@ static int get_device_dump(struct sk_buff *skb, struct netlink_callback *cb)
221221

222222
out:
223223
peer_put(last_peer_cursor);
224-
if (!ret && !done)
225-
next_peer_cursor = peer_rcu_get(next_peer_cursor);
224+
if (!ret && !done && next_peer_cursor)
225+
peer_get(next_peer_cursor);
226226
mutex_unlock(&wg->device_update_lock);
227227
rtnl_unlock();
228228

@@ -326,9 +326,11 @@ static int set_peer(struct wireguard_device *wg, struct nlattr **attrs)
326326
up_read(&wg->static_identity.lock);
327327

328328
ret = -ENOMEM;
329-
peer = peer_rcu_get(peer_create(wg, public_key, preshared_key));
329+
peer = peer_create(wg, public_key, preshared_key);
330330
if (!peer)
331331
goto out;
332+
/* Take additional reference, as though we've just been looked up. */
333+
peer_get(peer);
332334
}
333335

334336
ret = 0;

src/peer.c

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,14 @@ struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_
6363
return peer;
6464
}
6565

66-
struct wireguard_peer *peer_get(struct wireguard_peer *peer)
66+
struct wireguard_peer *peer_get_maybe_zero(struct wireguard_peer *peer)
6767
{
6868
RCU_LOCKDEP_WARN(!rcu_read_lock_bh_held(), "Taking peer reference without holding the RCU read lock");
6969
if (unlikely(!peer || !kref_get_unless_zero(&peer->refcount)))
7070
return NULL;
7171
return peer;
7272
}
7373

74-
struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer)
75-
{
76-
rcu_read_lock_bh();
77-
peer = peer_get(peer);
78-
rcu_read_unlock_bh();
79-
return peer;
80-
}
81-
8274
/* We have a separate "remove" function to get rid of the final reference because
8375
* peer_list, clearing handshakes, and flushing all require mutexes which requires
8476
* sleeping, which must only be done from certain contexts.

src/peer.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,11 @@ struct wireguard_peer {
6262

6363
struct wireguard_peer *peer_create(struct wireguard_device *wg, const u8 public_key[NOISE_PUBLIC_KEY_LEN], const u8 preshared_key[NOISE_SYMMETRIC_KEY_LEN]);
6464

65-
struct wireguard_peer *peer_get(struct wireguard_peer *peer);
66-
struct wireguard_peer *peer_rcu_get(struct wireguard_peer *peer);
67-
65+
struct wireguard_peer * __must_check peer_get_maybe_zero(struct wireguard_peer *peer);
66+
static inline void peer_get(struct wireguard_peer *peer)
67+
{
68+
kref_get(&peer->refcount);
69+
}
6870
void peer_put(struct wireguard_peer *peer);
6971
void peer_remove(struct wireguard_peer *peer);
7072
void peer_remove_all(struct wireguard_device *wg);

src/queueing.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,14 @@ static inline int queue_enqueue_per_device_and_peer(struct crypt_queue *device_q
132132

133133
static inline void queue_enqueue_per_peer(struct crypt_queue *queue, struct sk_buff *skb, enum packet_state state)
134134
{
135-
struct wireguard_peer *peer = peer_rcu_get(PACKET_PEER(skb));
136-
137135
atomic_set(&PACKET_CB(skb)->state, state);
138-
queue_work_on(cpumask_choose_online(&peer->serial_work_cpu, peer->internal_id), peer->device->packet_crypt_wq, &queue->work);
139-
peer_put(peer);
136+
queue_work_on(cpumask_choose_online(&PACKET_PEER(skb)->serial_work_cpu, PACKET_PEER(skb)->internal_id), PACKET_PEER(skb)->device->packet_crypt_wq, &queue->work);
140137
}
141138

142139
static inline void queue_enqueue_per_peer_napi(struct crypt_queue *queue, struct sk_buff *skb, enum packet_state state)
143140
{
144-
struct wireguard_peer *peer = peer_rcu_get(PACKET_PEER(skb));
145-
146141
atomic_set(&PACKET_CB(skb)->state, state);
147-
napi_schedule(&peer->napi);
148-
peer_put(peer);
142+
napi_schedule(&PACKET_PEER(skb)->napi);
149143
}
150144

151145
#ifdef DEBUG

src/receive.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ static void packet_consume_data(struct wireguard_device *wg, struct sk_buff *skb
448448
return;
449449
}
450450

451-
/* The call to index_hashtable_lookup gives us a reference to its underlying peer, so we don't need to call peer_rcu_get(). */
451+
/* The call to index_hashtable_lookup gives us a reference to its underlying peer, so we don't need to call peer_get(). */
452452
peer = PACKET_PEER(skb);
453453

454454
ret = queue_enqueue_per_device_and_peer(&wg->decrypt_queue, &peer->rx_queue, skb, wg->packet_crypt_wq, &wg->decrypt_queue.last_cpu);

src/send.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ void packet_send_queued_handshake_initiation(struct wireguard_peer *peer, bool i
6161
if (!has_expired(peer->last_sent_handshake, REKEY_TIMEOUT))
6262
return;
6363

64-
peer = peer_rcu_get(peer);
64+
peer_get(peer);
6565
/* Queues up calling packet_send_queued_handshakes(peer), where we do a peer_put(peer) after: */
6666
if (!queue_work(peer->device->handshake_send_wq, &peer->transmit_handshake_work))
6767
peer_put(peer); /* If the work was already queued, we want to drop the extra reference */
@@ -320,7 +320,7 @@ void packet_send_staged_packets(struct wireguard_peer *peer)
320320
}
321321

322322
packets.prev->next = NULL;
323-
peer_rcu_get(keypair->entry.peer);
323+
peer_get(keypair->entry.peer);
324324
PACKET_CB(packets.next)->keypair = keypair;
325325
packet_create_data(packets.next);
326326
return;

src/timers.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@
2020
*/
2121

2222
#define peer_get_from_timer(timer_name) \
23-
struct wireguard_peer *peer = peer_rcu_get(from_timer(peer, timer, timer_name)); \
23+
struct wireguard_peer *peer; \
24+
rcu_read_lock_bh(); \
25+
peer = peer_get_maybe_zero(from_timer(peer, timer, timer_name)); \
26+
rcu_read_unlock_bh(); \
2427
if (unlikely(!peer)) \
2528
return;
2629

0 commit comments

Comments
 (0)