Blame view

net/rxrpc/peer_object.c 12.5 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
be6e6707f   David Howells   rxrpc: Rework pee...
2
  /* RxRPC remote transport endpoint record management
17926a793   David Howells   [AF_RXRPC]: Provi...
3
   *
be6e6707f   David Howells   rxrpc: Rework pee...
4
   * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved.
17926a793   David Howells   [AF_RXRPC]: Provi...
5
   * Written by David Howells (dhowells@redhat.com)
17926a793   David Howells   [AF_RXRPC]: Provi...
6
   */
9b6d53985   Joe Perches   rxrpc: Use pr_<le...
7
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
17926a793   David Howells   [AF_RXRPC]: Provi...
8
9
10
11
12
  #include <linux/module.h>
  #include <linux/net.h>
  #include <linux/skbuff.h>
  #include <linux/udp.h>
  #include <linux/in.h>
75b54cb57   David Howells   rxrpc: Add IPv6 s...
13
  #include <linux/in6.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
14
  #include <linux/slab.h>
be6e6707f   David Howells   rxrpc: Rework pee...
15
  #include <linux/hashtable.h>
17926a793   David Howells   [AF_RXRPC]: Provi...
16
17
18
  #include <net/sock.h>
  #include <net/af_rxrpc.h>
  #include <net/ip.h>
224711df5   David Howells   [AF_RXRPC]: Sort ...
19
  #include <net/route.h>
75b54cb57   David Howells   rxrpc: Add IPv6 s...
20
  #include <net/ip6_route.h>
17926a793   David Howells   [AF_RXRPC]: Provi...
21
  #include "ar-internal.h"
be6e6707f   David Howells   rxrpc: Rework pee...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /*
   * Hash a peer key.
   */
  static unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local,
  					 const struct sockaddr_rxrpc *srx)
  {
  	const u16 *p;
  	unsigned int i, size;
  	unsigned long hash_key;
  
  	_enter("");
  
  	hash_key = (unsigned long)local / __alignof__(*local);
  	hash_key += srx->transport_type;
  	hash_key += srx->transport_len;
  	hash_key += srx->transport.family;
  
  	switch (srx->transport.family) {
  	case AF_INET:
  		hash_key += (u16 __force)srx->transport.sin.sin_port;
  		size = sizeof(srx->transport.sin.sin_addr);
  		p = (u16 *)&srx->transport.sin.sin_addr;
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
45
  #ifdef CONFIG_AF_RXRPC_IPV6
75b54cb57   David Howells   rxrpc: Add IPv6 s...
46
47
48
49
50
  	case AF_INET6:
  		hash_key += (u16 __force)srx->transport.sin.sin_port;
  		size = sizeof(srx->transport.sin6.sin6_addr);
  		p = (u16 *)&srx->transport.sin6.sin6_addr;
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
51
  #endif
2f9f9f521   Arnd Bergmann   rxrpc: fix uninit...
52
53
54
55
  	default:
  		WARN(1, "AF_RXRPC: Unsupported transport address family
  ");
  		return 0;
be6e6707f   David Howells   rxrpc: Rework pee...
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
  	}
  
  	/* Step through the peer address in 16-bit portions for speed */
  	for (i = 0; i < size; i += sizeof(*p), p++)
  		hash_key += *p;
  
  	_leave(" 0x%lx", hash_key);
  	return hash_key;
  }
  
  /*
   * Compare a peer to a key.  Return -ve, 0 or +ve to indicate less than, same
   * or greater than.
   *
   * Unfortunately, the primitives in linux/hashtable.h don't allow for sorted
   * buckets and mid-bucket insertion, so we don't make full use of this
   * information at this point.
   */
  static long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer,
  			       struct rxrpc_local *local,
  			       const struct sockaddr_rxrpc *srx,
  			       unsigned long hash_key)
  {
  	long diff;
  
  	diff = ((peer->hash_key - hash_key) ?:
  		((unsigned long)peer->local - (unsigned long)local) ?:
  		(peer->srx.transport_type - srx->transport_type) ?:
  		(peer->srx.transport_len - srx->transport_len) ?:
  		(peer->srx.transport.family - srx->transport.family));
  	if (diff != 0)
  		return diff;
  
  	switch (srx->transport.family) {
  	case AF_INET:
  		return ((u16 __force)peer->srx.transport.sin.sin_port -
  			(u16 __force)srx->transport.sin.sin_port) ?:
  			memcmp(&peer->srx.transport.sin.sin_addr,
  			       &srx->transport.sin.sin_addr,
  			       sizeof(struct in_addr));
d19127473   David Howells   rxrpc: Make IPv6 ...
96
  #ifdef CONFIG_AF_RXRPC_IPV6
75b54cb57   David Howells   rxrpc: Add IPv6 s...
97
98
99
100
101
102
  	case AF_INET6:
  		return ((u16 __force)peer->srx.transport.sin6.sin6_port -
  			(u16 __force)srx->transport.sin6.sin6_port) ?:
  			memcmp(&peer->srx.transport.sin6.sin6_addr,
  			       &srx->transport.sin6.sin6_addr,
  			       sizeof(struct in6_addr));
d19127473   David Howells   rxrpc: Make IPv6 ...
103
  #endif
be6e6707f   David Howells   rxrpc: Rework pee...
104
105
106
107
108
109
110
111
112
113
114
115
116
117
  	default:
  		BUG();
  	}
  }
  
  /*
   * Look up a remote transport endpoint for the specified address using RCU.
   */
  static struct rxrpc_peer *__rxrpc_lookup_peer_rcu(
  	struct rxrpc_local *local,
  	const struct sockaddr_rxrpc *srx,
  	unsigned long hash_key)
  {
  	struct rxrpc_peer *peer;
2baec2c3f   David Howells   rxrpc: Support ne...
118
  	struct rxrpc_net *rxnet = local->rxnet;
be6e6707f   David Howells   rxrpc: Rework pee...
119

2baec2c3f   David Howells   rxrpc: Support ne...
120
  	hash_for_each_possible_rcu(rxnet->peer_hash, peer, hash_link, hash_key) {
0099dc589   David Howells   rxrpc: Make servi...
121
122
  		if (rxrpc_peer_cmp_key(peer, local, srx, hash_key) == 0 &&
  		    atomic_read(&peer->usage) > 0)
be6e6707f   David Howells   rxrpc: Rework pee...
123
  			return peer;
be6e6707f   David Howells   rxrpc: Rework pee...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
  	}
  
  	return NULL;
  }
  
  /*
   * Look up a remote transport endpoint for the specified address using RCU.
   */
  struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
  					 const struct sockaddr_rxrpc *srx)
  {
  	struct rxrpc_peer *peer;
  	unsigned long hash_key = rxrpc_peer_hash_key(local, srx);
  
  	peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
  	if (peer) {
75b54cb57   David Howells   rxrpc: Add IPv6 s...
140
  		_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
be6e6707f   David Howells   rxrpc: Rework pee...
141
142
143
144
  		_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
  	}
  	return peer;
  }
17926a793   David Howells   [AF_RXRPC]: Provi...
145
146
  
  /*
224711df5   David Howells   [AF_RXRPC]: Sort ...
147
148
149
   * assess the MTU size for the network interface through which this peer is
   * reached
   */
5e33a23ba   David Howells   rxrpc: Fix some m...
150
151
  static void rxrpc_assess_MTU_size(struct rxrpc_sock *rx,
  				  struct rxrpc_peer *peer)
224711df5   David Howells   [AF_RXRPC]: Sort ...
152
  {
5e33a23ba   David Howells   rxrpc: Fix some m...
153
  	struct net *net = sock_net(&rx->sk);
75b54cb57   David Howells   rxrpc: Add IPv6 s...
154
  	struct dst_entry *dst;
224711df5   David Howells   [AF_RXRPC]: Sort ...
155
  	struct rtable *rt;
75b54cb57   David Howells   rxrpc: Add IPv6 s...
156
157
  	struct flowi fl;
  	struct flowi4 *fl4 = &fl.u.ip4;
d19127473   David Howells   rxrpc: Make IPv6 ...
158
  #ifdef CONFIG_AF_RXRPC_IPV6
75b54cb57   David Howells   rxrpc: Add IPv6 s...
159
  	struct flowi6 *fl6 = &fl.u.ip6;
d19127473   David Howells   rxrpc: Make IPv6 ...
160
  #endif
224711df5   David Howells   [AF_RXRPC]: Sort ...
161
162
  
  	peer->if_mtu = 1500;
75b54cb57   David Howells   rxrpc: Add IPv6 s...
163
164
165
166
  	memset(&fl, 0, sizeof(fl));
  	switch (peer->srx.transport.family) {
  	case AF_INET:
  		rt = ip_route_output_ports(
5e33a23ba   David Howells   rxrpc: Fix some m...
167
  			net, fl4, NULL,
75b54cb57   David Howells   rxrpc: Add IPv6 s...
168
169
170
171
172
173
174
175
  			peer->srx.transport.sin.sin_addr.s_addr, 0,
  			htons(7000), htons(7001), IPPROTO_UDP, 0, 0);
  		if (IS_ERR(rt)) {
  			_leave(" [route err %ld]", PTR_ERR(rt));
  			return;
  		}
  		dst = &rt->dst;
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
176
  #ifdef CONFIG_AF_RXRPC_IPV6
75b54cb57   David Howells   rxrpc: Add IPv6 s...
177
178
179
180
181
182
183
184
  	case AF_INET6:
  		fl6->flowi6_iif = LOOPBACK_IFINDEX;
  		fl6->flowi6_scope = RT_SCOPE_UNIVERSE;
  		fl6->flowi6_proto = IPPROTO_UDP;
  		memcpy(&fl6->daddr, &peer->srx.transport.sin6.sin6_addr,
  		       sizeof(struct in6_addr));
  		fl6->fl6_dport = htons(7001);
  		fl6->fl6_sport = htons(7000);
5e33a23ba   David Howells   rxrpc: Fix some m...
185
  		dst = ip6_route_output(net, NULL, fl6);
07096f612   David Howells   rxrpc: Fix checki...
186
187
  		if (dst->error) {
  			_leave(" [route err %d]", dst->error);
75b54cb57   David Howells   rxrpc: Add IPv6 s...
188
189
190
  			return;
  		}
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
191
  #endif
75b54cb57   David Howells   rxrpc: Add IPv6 s...
192
193
194
  
  	default:
  		BUG();
224711df5   David Howells   [AF_RXRPC]: Sort ...
195
  	}
75b54cb57   David Howells   rxrpc: Add IPv6 s...
196
197
  	peer->if_mtu = dst_mtu(dst);
  	dst_release(dst);
224711df5   David Howells   [AF_RXRPC]: Sort ...
198

a6a62b69b   David Howells   AF_RXRPC: reduce ...
199
  	_leave(" [if_mtu %u]", peer->if_mtu);
224711df5   David Howells   [AF_RXRPC]: Sort ...
200
201
202
  }
  
  /*
be6e6707f   David Howells   rxrpc: Rework pee...
203
   * Allocate a peer.
17926a793   David Howells   [AF_RXRPC]: Provi...
204
   */
be6e6707f   David Howells   rxrpc: Rework pee...
205
  struct rxrpc_peer *rxrpc_alloc_peer(struct rxrpc_local *local, gfp_t gfp)
17926a793   David Howells   [AF_RXRPC]: Provi...
206
  {
033b2c7f0   David Howells   rxrpc: Add missin...
207
  	const void *here = __builtin_return_address(0);
17926a793   David Howells   [AF_RXRPC]: Provi...
208
209
210
211
212
213
  	struct rxrpc_peer *peer;
  
  	_enter("");
  
  	peer = kzalloc(sizeof(struct rxrpc_peer), gfp);
  	if (peer) {
be6e6707f   David Howells   rxrpc: Rework pee...
214
  		atomic_set(&peer->usage, 1);
9ebeddef5   David Howells   rxrpc: rxrpc_peer...
215
  		peer->local = rxrpc_get_local(local);
f66d74901   David Howells   rxrpc: Use the pe...
216
  		INIT_HLIST_HEAD(&peer->error_targets);
aa390bbe2   David Howells   rxrpc: Kill off t...
217
  		peer->service_conns = RB_ROOT;
8496af50e   David Howells   rxrpc: Use RCU to...
218
  		seqlock_init(&peer->service_conn_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
219
  		spin_lock_init(&peer->lock);
c1e15b494   David Howells   rxrpc: Fix the pa...
220
  		spin_lock_init(&peer->rtt_input_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
221
  		peer->debug_id = atomic_inc_return(&rxrpc_debug_id);
f7aec129a   David Howells   rxrpc: Cache the ...
222

c410bf019   David Howells   rxrpc: Fix the ex...
223
  		rxrpc_peer_init_rtt(peer);
f7aec129a   David Howells   rxrpc: Cache the ...
224
225
226
227
228
229
  		if (RXRPC_TX_SMSS > 2190)
  			peer->cong_cwnd = 2;
  		else if (RXRPC_TX_SMSS > 1095)
  			peer->cong_cwnd = 3;
  		else
  			peer->cong_cwnd = 4;
2f184393e   David S. Miller   Merge git://git.k...
230
  		trace_rxrpc_peer(peer->debug_id, rxrpc_peer_new, 1, here);
be6e6707f   David Howells   rxrpc: Rework pee...
231
232
233
234
235
236
237
  	}
  
  	_leave(" = %p", peer);
  	return peer;
  }
  
  /*
248f219cb   David Howells   rxrpc: Rewrite th...
238
239
   * Initialise peer record.
   */
5e33a23ba   David Howells   rxrpc: Fix some m...
240
241
  static void rxrpc_init_peer(struct rxrpc_sock *rx, struct rxrpc_peer *peer,
  			    unsigned long hash_key)
248f219cb   David Howells   rxrpc: Rewrite th...
242
  {
08a39685a   David Howells   rxrpc: Make sure ...
243
  	peer->hash_key = hash_key;
5e33a23ba   David Howells   rxrpc: Fix some m...
244
  	rxrpc_assess_MTU_size(rx, peer);
248f219cb   David Howells   rxrpc: Rewrite th...
245
  	peer->mtu = peer->if_mtu;
0d4b103c0   David Howells   rxrpc: Reduce the...
246
  	peer->rtt_last_req = ktime_get_real();
248f219cb   David Howells   rxrpc: Rewrite th...
247

75b54cb57   David Howells   rxrpc: Add IPv6 s...
248
249
  	switch (peer->srx.transport.family) {
  	case AF_INET:
248f219cb   David Howells   rxrpc: Rewrite th...
250
  		peer->hdrsize = sizeof(struct iphdr);
75b54cb57   David Howells   rxrpc: Add IPv6 s...
251
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
252
  #ifdef CONFIG_AF_RXRPC_IPV6
75b54cb57   David Howells   rxrpc: Add IPv6 s...
253
254
255
  	case AF_INET6:
  		peer->hdrsize = sizeof(struct ipv6hdr);
  		break;
d19127473   David Howells   rxrpc: Make IPv6 ...
256
  #endif
75b54cb57   David Howells   rxrpc: Add IPv6 s...
257
258
259
260
261
262
263
264
265
  	default:
  		BUG();
  	}
  
  	switch (peer->srx.transport_type) {
  	case SOCK_DGRAM:
  		peer->hdrsize += sizeof(struct udphdr);
  		break;
  	default:
248f219cb   David Howells   rxrpc: Rewrite th...
266
267
268
269
270
271
272
273
  		BUG();
  	}
  
  	peer->hdrsize += sizeof(struct rxrpc_wire_header);
  	peer->maxdata = peer->mtu - peer->hdrsize;
  }
  
  /*
be6e6707f   David Howells   rxrpc: Rework pee...
274
275
   * Set up a new peer.
   */
5e33a23ba   David Howells   rxrpc: Fix some m...
276
277
  static struct rxrpc_peer *rxrpc_create_peer(struct rxrpc_sock *rx,
  					    struct rxrpc_local *local,
be6e6707f   David Howells   rxrpc: Rework pee...
278
279
280
281
282
283
284
285
286
287
  					    struct sockaddr_rxrpc *srx,
  					    unsigned long hash_key,
  					    gfp_t gfp)
  {
  	struct rxrpc_peer *peer;
  
  	_enter("");
  
  	peer = rxrpc_alloc_peer(local, gfp);
  	if (peer) {
17926a793   David Howells   [AF_RXRPC]: Provi...
288
  		memcpy(&peer->srx, srx, sizeof(*srx));
5e33a23ba   David Howells   rxrpc: Fix some m...
289
  		rxrpc_init_peer(rx, peer, hash_key);
248f219cb   David Howells   rxrpc: Rewrite th...
290
  	}
17926a793   David Howells   [AF_RXRPC]: Provi...
291

248f219cb   David Howells   rxrpc: Rewrite th...
292
293
294
  	_leave(" = %p", peer);
  	return peer;
  }
17926a793   David Howells   [AF_RXRPC]: Provi...
295

248f219cb   David Howells   rxrpc: Rewrite th...
296
  /*
0099dc589   David Howells   rxrpc: Make servi...
297
298
299
   * Set up a new incoming peer.  There shouldn't be any other matching peers
   * since we've already done a search in the list from the non-reentrant context
   * (the data_ready handler) that is the only place we can add new peers.
248f219cb   David Howells   rxrpc: Rewrite th...
300
   */
5e33a23ba   David Howells   rxrpc: Fix some m...
301
302
  void rxrpc_new_incoming_peer(struct rxrpc_sock *rx, struct rxrpc_local *local,
  			     struct rxrpc_peer *peer)
248f219cb   David Howells   rxrpc: Rewrite th...
303
  {
2baec2c3f   David Howells   rxrpc: Support ne...
304
  	struct rxrpc_net *rxnet = local->rxnet;
248f219cb   David Howells   rxrpc: Rewrite th...
305
  	unsigned long hash_key;
0099dc589   David Howells   rxrpc: Make servi...
306
  	hash_key = rxrpc_peer_hash_key(local, &peer->srx);
5e33a23ba   David Howells   rxrpc: Fix some m...
307
  	rxrpc_init_peer(rx, peer, hash_key);
248f219cb   David Howells   rxrpc: Rewrite th...
308

2baec2c3f   David Howells   rxrpc: Support ne...
309
  	spin_lock(&rxnet->peer_hash_lock);
0099dc589   David Howells   rxrpc: Make servi...
310
311
  	hash_add_rcu(rxnet->peer_hash, &peer->hash_link, hash_key);
  	list_add_tail(&peer->keepalive_link, &rxnet->peer_keepalive_new);
2baec2c3f   David Howells   rxrpc: Support ne...
312
  	spin_unlock(&rxnet->peer_hash_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
313
314
315
316
317
  }
  
  /*
   * obtain a remote transport endpoint for the specified address
   */
5e33a23ba   David Howells   rxrpc: Fix some m...
318
319
  struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_sock *rx,
  				     struct rxrpc_local *local,
be6e6707f   David Howells   rxrpc: Rework pee...
320
  				     struct sockaddr_rxrpc *srx, gfp_t gfp)
17926a793   David Howells   [AF_RXRPC]: Provi...
321
322
  {
  	struct rxrpc_peer *peer, *candidate;
2baec2c3f   David Howells   rxrpc: Support ne...
323
  	struct rxrpc_net *rxnet = local->rxnet;
be6e6707f   David Howells   rxrpc: Rework pee...
324
  	unsigned long hash_key = rxrpc_peer_hash_key(local, srx);
17926a793   David Howells   [AF_RXRPC]: Provi...
325

75b54cb57   David Howells   rxrpc: Add IPv6 s...
326
  	_enter("{%pISp}", &srx->transport);
17926a793   David Howells   [AF_RXRPC]: Provi...
327
328
  
  	/* search the peer list first */
be6e6707f   David Howells   rxrpc: Rework pee...
329
330
331
332
333
334
335
336
337
338
  	rcu_read_lock();
  	peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
  	if (peer && !rxrpc_get_peer_maybe(peer))
  		peer = NULL;
  	rcu_read_unlock();
  
  	if (!peer) {
  		/* The peer is not yet present in hash - create a candidate
  		 * for a new record and then redo the search.
  		 */
5e33a23ba   David Howells   rxrpc: Fix some m...
339
  		candidate = rxrpc_create_peer(rx, local, srx, hash_key, gfp);
be6e6707f   David Howells   rxrpc: Rework pee...
340
341
342
343
  		if (!candidate) {
  			_leave(" = NULL [nomem]");
  			return NULL;
  		}
17926a793   David Howells   [AF_RXRPC]: Provi...
344

2baec2c3f   David Howells   rxrpc: Support ne...
345
  		spin_lock_bh(&rxnet->peer_hash_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
346

be6e6707f   David Howells   rxrpc: Rework pee...
347
348
349
350
  		/* Need to check that we aren't racing with someone else */
  		peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
  		if (peer && !rxrpc_get_peer_maybe(peer))
  			peer = NULL;
ace45bec6   David Howells   rxrpc: Fix firewa...
351
  		if (!peer) {
2baec2c3f   David Howells   rxrpc: Support ne...
352
  			hash_add_rcu(rxnet->peer_hash,
be6e6707f   David Howells   rxrpc: Rework pee...
353
  				     &candidate->hash_link, hash_key);
330bdcfad   David Howells   rxrpc: Fix the ke...
354
355
  			list_add_tail(&candidate->keepalive_link,
  				      &rxnet->peer_keepalive_new);
ace45bec6   David Howells   rxrpc: Fix firewa...
356
  		}
17926a793   David Howells   [AF_RXRPC]: Provi...
357

2baec2c3f   David Howells   rxrpc: Support ne...
358
  		spin_unlock_bh(&rxnet->peer_hash_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
359

be6e6707f   David Howells   rxrpc: Rework pee...
360
361
362
363
364
  		if (peer)
  			kfree(candidate);
  		else
  			peer = candidate;
  	}
17926a793   David Howells   [AF_RXRPC]: Provi...
365

75b54cb57   David Howells   rxrpc: Add IPv6 s...
366
  	_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
17926a793   David Howells   [AF_RXRPC]: Provi...
367

be6e6707f   David Howells   rxrpc: Rework pee...
368
  	_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
17926a793   David Howells   [AF_RXRPC]: Provi...
369
  	return peer;
17926a793   David Howells   [AF_RXRPC]: Provi...
370
371
372
  }
  
  /*
1159d4b49   David Howells   rxrpc: Add a trac...
373
   * Get a ref on a peer record.
17926a793   David Howells   [AF_RXRPC]: Provi...
374
   */
1159d4b49   David Howells   rxrpc: Add a trac...
375
376
377
378
379
380
  struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer)
  {
  	const void *here = __builtin_return_address(0);
  	int n;
  
  	n = atomic_inc_return(&peer->usage);
55f6c98e3   David Howells   rxrpc: Fix trace-...
381
  	trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n, here);
1159d4b49   David Howells   rxrpc: Add a trac...
382
383
384
385
386
387
388
389
390
391
392
  	return peer;
  }
  
  /*
   * Get a ref on a peer record unless its usage has already reached 0.
   */
  struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer)
  {
  	const void *here = __builtin_return_address(0);
  
  	if (peer) {
bfc18e389   Mark Rutland   atomics/treewide:...
393
  		int n = atomic_fetch_add_unless(&peer->usage, 1, 0);
1159d4b49   David Howells   rxrpc: Add a trac...
394
  		if (n > 0)
55f6c98e3   David Howells   rxrpc: Fix trace-...
395
  			trace_rxrpc_peer(peer->debug_id, rxrpc_peer_got, n + 1, here);
1159d4b49   David Howells   rxrpc: Add a trac...
396
397
398
399
400
401
402
  		else
  			peer = NULL;
  	}
  	return peer;
  }
  
  /*
1159d4b49   David Howells   rxrpc: Add a trac...
403
404
405
   * Discard a peer record.
   */
  static void __rxrpc_put_peer(struct rxrpc_peer *peer)
17926a793   David Howells   [AF_RXRPC]: Provi...
406
  {
2baec2c3f   David Howells   rxrpc: Support ne...
407
  	struct rxrpc_net *rxnet = peer->local->rxnet;
f66d74901   David Howells   rxrpc: Use the pe...
408
  	ASSERT(hlist_empty(&peer->error_targets));
17926a793   David Howells   [AF_RXRPC]: Provi...
409

2baec2c3f   David Howells   rxrpc: Support ne...
410
  	spin_lock_bh(&rxnet->peer_hash_lock);
be6e6707f   David Howells   rxrpc: Rework pee...
411
  	hash_del_rcu(&peer->hash_link);
330bdcfad   David Howells   rxrpc: Fix the ke...
412
  	list_del_init(&peer->keepalive_link);
2baec2c3f   David Howells   rxrpc: Support ne...
413
  	spin_unlock_bh(&rxnet->peer_hash_lock);
17926a793   David Howells   [AF_RXRPC]: Provi...
414

9ebeddef5   David Howells   rxrpc: rxrpc_peer...
415
  	rxrpc_put_local(peer->local);
be6e6707f   David Howells   rxrpc: Rework pee...
416
  	kfree_rcu(peer, rcu);
17926a793   David Howells   [AF_RXRPC]: Provi...
417
  }
8324f0bcf   David Howells   rxrpc: Provide a ...
418

1159d4b49   David Howells   rxrpc: Add a trac...
419
420
421
422
423
424
  /*
   * Drop a ref on a peer record.
   */
  void rxrpc_put_peer(struct rxrpc_peer *peer)
  {
  	const void *here = __builtin_return_address(0);
55f6c98e3   David Howells   rxrpc: Fix trace-...
425
  	unsigned int debug_id;
1159d4b49   David Howells   rxrpc: Add a trac...
426
427
428
  	int n;
  
  	if (peer) {
55f6c98e3   David Howells   rxrpc: Fix trace-...
429
  		debug_id = peer->debug_id;
1159d4b49   David Howells   rxrpc: Add a trac...
430
  		n = atomic_dec_return(&peer->usage);
55f6c98e3   David Howells   rxrpc: Fix trace-...
431
  		trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here);
1159d4b49   David Howells   rxrpc: Add a trac...
432
433
434
435
  		if (n == 0)
  			__rxrpc_put_peer(peer);
  	}
  }
17226f124   David Howells   rxrpc: Fix leak o...
436
  /*
60034d3d1   David Howells   rxrpc: Fix potent...
437
438
439
440
441
442
   * Drop a ref on a peer record where the caller already holds the
   * peer_hash_lock.
   */
  void rxrpc_put_peer_locked(struct rxrpc_peer *peer)
  {
  	const void *here = __builtin_return_address(0);
55f6c98e3   David Howells   rxrpc: Fix trace-...
443
  	unsigned int debug_id = peer->debug_id;
60034d3d1   David Howells   rxrpc: Fix potent...
444
445
446
  	int n;
  
  	n = atomic_dec_return(&peer->usage);
55f6c98e3   David Howells   rxrpc: Fix trace-...
447
  	trace_rxrpc_peer(debug_id, rxrpc_peer_put, n, here);
60034d3d1   David Howells   rxrpc: Fix potent...
448
449
450
  	if (n == 0) {
  		hash_del_rcu(&peer->hash_link);
  		list_del_init(&peer->keepalive_link);
9ebeddef5   David Howells   rxrpc: rxrpc_peer...
451
  		rxrpc_put_local(peer->local);
60034d3d1   David Howells   rxrpc: Fix potent...
452
453
454
455
456
  		kfree_rcu(peer, rcu);
  	}
  }
  
  /*
17226f124   David Howells   rxrpc: Fix leak o...
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
   * Make sure all peer records have been discarded.
   */
  void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet)
  {
  	struct rxrpc_peer *peer;
  	int i;
  
  	for (i = 0; i < HASH_SIZE(rxnet->peer_hash); i++) {
  		if (hlist_empty(&rxnet->peer_hash[i]))
  			continue;
  
  		hlist_for_each_entry(peer, &rxnet->peer_hash[i], hash_link) {
  			pr_err("Leaked peer %u {%u} %pISp
  ",
  			       peer->debug_id,
  			       atomic_read(&peer->usage),
  			       &peer->srx.transport);
  		}
  	}
  }
8324f0bcf   David Howells   rxrpc: Provide a ...
477
478
479
480
481
482
483
484
485
486
487
488
489
490
  /**
   * rxrpc_kernel_get_peer - Get the peer address of a call
   * @sock: The socket on which the call is in progress.
   * @call: The call to query
   * @_srx: Where to place the result
   *
   * Get the address of the remote peer in a call.
   */
  void rxrpc_kernel_get_peer(struct socket *sock, struct rxrpc_call *call,
  			   struct sockaddr_rxrpc *_srx)
  {
  	*_srx = call->peer->srx;
  }
  EXPORT_SYMBOL(rxrpc_kernel_get_peer);
f4d15fb6f   David Howells   rxrpc: Provide fu...
491
492
  
  /**
c410bf019   David Howells   rxrpc: Fix the ex...
493
   * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT
f4d15fb6f   David Howells   rxrpc: Provide fu...
494
495
   * @sock: The socket on which the call is in progress.
   * @call: The call to query
1d4adfaf6   David Howells   rxrpc: Make rxrpc...
496
   * @_srtt: Where to store the SRTT value.
f4d15fb6f   David Howells   rxrpc: Provide fu...
497
   *
1d4adfaf6   David Howells   rxrpc: Make rxrpc...
498
   * Get the call's peer smoothed RTT in uS.
f4d15fb6f   David Howells   rxrpc: Provide fu...
499
   */
1d4adfaf6   David Howells   rxrpc: Make rxrpc...
500
501
  bool rxrpc_kernel_get_srtt(struct socket *sock, struct rxrpc_call *call,
  			   u32 *_srtt)
f4d15fb6f   David Howells   rxrpc: Provide fu...
502
  {
1d4adfaf6   David Howells   rxrpc: Make rxrpc...
503
504
505
506
507
508
509
510
511
  	struct rxrpc_peer *peer = call->peer;
  
  	if (peer->rtt_count == 0) {
  		*_srtt = 1000000; /* 1S */
  		return false;
  	}
  
  	*_srtt = call->peer->srtt_us >> 3;
  	return true;
f4d15fb6f   David Howells   rxrpc: Provide fu...
512
  }
c410bf019   David Howells   rxrpc: Fix the ex...
513
  EXPORT_SYMBOL(rxrpc_kernel_get_srtt);