.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* RxRPC virtual connection handler, common bits. |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * Written by David Howells (dhowells@redhat.com) |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the License, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
---|
.. | .. |
---|
45 | 41 | conn = kzalloc(sizeof(struct rxrpc_connection), gfp); |
---|
46 | 42 | if (conn) { |
---|
47 | 43 | INIT_LIST_HEAD(&conn->cache_link); |
---|
48 | | - spin_lock_init(&conn->channel_lock); |
---|
49 | | - INIT_LIST_HEAD(&conn->waiting_calls); |
---|
50 | 44 | timer_setup(&conn->timer, &rxrpc_connection_timer, 0); |
---|
51 | 45 | INIT_WORK(&conn->processor, &rxrpc_process_connection); |
---|
52 | 46 | INIT_LIST_HEAD(&conn->proc_link); |
---|
.. | .. |
---|
86 | 80 | |
---|
87 | 81 | _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK); |
---|
88 | 82 | |
---|
89 | | - if (rxrpc_extract_addr_from_skb(local, &srx, skb) < 0) |
---|
| 83 | + if (rxrpc_extract_addr_from_skb(&srx, skb) < 0) |
---|
90 | 84 | goto not_found; |
---|
91 | 85 | |
---|
92 | | - /* We may have to handle mixing IPv4 and IPv6 */ |
---|
93 | | - if (srx.transport.family != local->srx.transport.family) { |
---|
| 86 | + if (srx.transport.family != local->srx.transport.family && |
---|
| 87 | + (srx.transport.family == AF_INET && |
---|
| 88 | + local->srx.transport.family != AF_INET6)) { |
---|
94 | 89 | pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", |
---|
95 | 90 | srx.transport.family, |
---|
96 | 91 | local->srx.transport.family); |
---|
.. | .. |
---|
110 | 105 | goto not_found; |
---|
111 | 106 | *_peer = peer; |
---|
112 | 107 | conn = rxrpc_find_service_conn_rcu(peer, skb); |
---|
113 | | - if (!conn || atomic_read(&conn->usage) == 0) |
---|
| 108 | + if (!conn || refcount_read(&conn->ref) == 0) |
---|
114 | 109 | goto not_found; |
---|
115 | 110 | _leave(" = %p", conn); |
---|
116 | 111 | return conn; |
---|
.. | .. |
---|
120 | 115 | */ |
---|
121 | 116 | conn = idr_find(&rxrpc_client_conn_ids, |
---|
122 | 117 | sp->hdr.cid >> RXRPC_CIDSHIFT); |
---|
123 | | - if (!conn || atomic_read(&conn->usage) == 0) { |
---|
| 118 | + if (!conn || refcount_read(&conn->ref) == 0) { |
---|
124 | 119 | _debug("no conn"); |
---|
125 | 120 | goto not_found; |
---|
126 | 121 | } |
---|
.. | .. |
---|
189 | 184 | chan->last_type = RXRPC_PACKET_TYPE_ABORT; |
---|
190 | 185 | break; |
---|
191 | 186 | default: |
---|
192 | | - chan->last_abort = RX_USER_ABORT; |
---|
| 187 | + chan->last_abort = RX_CALL_DEAD; |
---|
193 | 188 | chan->last_type = RXRPC_PACKET_TYPE_ABORT; |
---|
194 | 189 | break; |
---|
195 | 190 | } |
---|
.. | .. |
---|
222 | 217 | } |
---|
223 | 218 | |
---|
224 | 219 | if (rxrpc_is_client_call(call)) |
---|
225 | | - return rxrpc_disconnect_client_call(call); |
---|
| 220 | + return rxrpc_disconnect_client_call(conn->bundle, call); |
---|
226 | 221 | |
---|
227 | | - spin_lock(&conn->channel_lock); |
---|
| 222 | + spin_lock(&conn->bundle->channel_lock); |
---|
228 | 223 | __rxrpc_disconnect_call(conn, call); |
---|
229 | | - spin_unlock(&conn->channel_lock); |
---|
| 224 | + spin_unlock(&conn->bundle->channel_lock); |
---|
230 | 225 | |
---|
231 | 226 | set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); |
---|
232 | 227 | conn->idle_timestamp = jiffies; |
---|
.. | .. |
---|
269 | 264 | bool rxrpc_queue_conn(struct rxrpc_connection *conn) |
---|
270 | 265 | { |
---|
271 | 266 | const void *here = __builtin_return_address(0); |
---|
272 | | - int n = atomic_fetch_add_unless(&conn->usage, 1, 0); |
---|
273 | | - if (n == 0) |
---|
| 267 | + int r; |
---|
| 268 | + |
---|
| 269 | + if (!__refcount_inc_not_zero(&conn->ref, &r)) |
---|
274 | 270 | return false; |
---|
275 | 271 | if (rxrpc_queue_work(&conn->processor)) |
---|
276 | | - trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, n + 1, here); |
---|
| 272 | + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, r + 1, here); |
---|
277 | 273 | else |
---|
278 | 274 | rxrpc_put_connection(conn); |
---|
279 | 275 | return true; |
---|
.. | .. |
---|
286 | 282 | { |
---|
287 | 283 | const void *here = __builtin_return_address(0); |
---|
288 | 284 | if (conn) { |
---|
289 | | - int n = atomic_read(&conn->usage); |
---|
| 285 | + int n = refcount_read(&conn->ref); |
---|
290 | 286 | |
---|
291 | 287 | trace_rxrpc_conn(conn->debug_id, rxrpc_conn_seen, n, here); |
---|
292 | 288 | } |
---|
.. | .. |
---|
295 | 291 | /* |
---|
296 | 292 | * Get a ref on a connection. |
---|
297 | 293 | */ |
---|
298 | | -void rxrpc_get_connection(struct rxrpc_connection *conn) |
---|
| 294 | +struct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *conn) |
---|
299 | 295 | { |
---|
300 | 296 | const void *here = __builtin_return_address(0); |
---|
301 | | - int n = atomic_inc_return(&conn->usage); |
---|
| 297 | + int r; |
---|
302 | 298 | |
---|
303 | | - trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n, here); |
---|
| 299 | + __refcount_inc(&conn->ref, &r); |
---|
| 300 | + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r, here); |
---|
| 301 | + return conn; |
---|
304 | 302 | } |
---|
305 | 303 | |
---|
306 | 304 | /* |
---|
.. | .. |
---|
310 | 308 | rxrpc_get_connection_maybe(struct rxrpc_connection *conn) |
---|
311 | 309 | { |
---|
312 | 310 | const void *here = __builtin_return_address(0); |
---|
| 311 | + int r; |
---|
313 | 312 | |
---|
314 | 313 | if (conn) { |
---|
315 | | - int n = atomic_fetch_add_unless(&conn->usage, 1, 0); |
---|
316 | | - if (n > 0) |
---|
317 | | - trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, n + 1, here); |
---|
| 314 | + if (__refcount_inc_not_zero(&conn->ref, &r)) |
---|
| 315 | + trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r + 1, here); |
---|
318 | 316 | else |
---|
319 | 317 | conn = NULL; |
---|
320 | 318 | } |
---|
.. | .. |
---|
338 | 336 | { |
---|
339 | 337 | const void *here = __builtin_return_address(0); |
---|
340 | 338 | unsigned int debug_id = conn->debug_id; |
---|
341 | | - int n; |
---|
| 339 | + int r; |
---|
342 | 340 | |
---|
343 | | - n = atomic_dec_return(&conn->usage); |
---|
344 | | - trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, n, here); |
---|
345 | | - ASSERTCMP(n, >=, 0); |
---|
346 | | - if (n == 1) |
---|
| 341 | + __refcount_dec(&conn->ref, &r); |
---|
| 342 | + trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, r - 1, here); |
---|
| 343 | + if (r - 1 == 1) |
---|
347 | 344 | rxrpc_set_service_reap_timer(conn->params.local->rxnet, |
---|
348 | 345 | jiffies + rxrpc_connection_expiry); |
---|
349 | 346 | } |
---|
.. | .. |
---|
356 | 353 | struct rxrpc_connection *conn = |
---|
357 | 354 | container_of(rcu, struct rxrpc_connection, rcu); |
---|
358 | 355 | |
---|
359 | | - _enter("{%d,u=%d}", conn->debug_id, atomic_read(&conn->usage)); |
---|
| 356 | + _enter("{%d,u=%d}", conn->debug_id, refcount_read(&conn->ref)); |
---|
360 | 357 | |
---|
361 | | - ASSERTCMP(atomic_read(&conn->usage), ==, 0); |
---|
| 358 | + ASSERTCMP(refcount_read(&conn->ref), ==, 0); |
---|
362 | 359 | |
---|
363 | 360 | _net("DESTROY CONN %d", conn->debug_id); |
---|
364 | 361 | |
---|
.. | .. |
---|
368 | 365 | conn->security->clear(conn); |
---|
369 | 366 | key_put(conn->params.key); |
---|
370 | 367 | key_put(conn->server_key); |
---|
| 368 | + rxrpc_put_bundle(conn->bundle); |
---|
371 | 369 | rxrpc_put_peer(conn->params.peer); |
---|
372 | 370 | |
---|
373 | 371 | if (atomic_dec_and_test(&conn->params.local->rxnet->nr_conns)) |
---|
.. | .. |
---|
397 | 395 | |
---|
398 | 396 | write_lock(&rxnet->conn_lock); |
---|
399 | 397 | list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { |
---|
400 | | - ASSERTCMP(atomic_read(&conn->usage), >, 0); |
---|
401 | | - if (likely(atomic_read(&conn->usage) > 1)) |
---|
| 398 | + ASSERTCMP(refcount_read(&conn->ref), >, 0); |
---|
| 399 | + if (likely(refcount_read(&conn->ref) > 1)) |
---|
402 | 400 | continue; |
---|
403 | 401 | if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) |
---|
404 | 402 | continue; |
---|
.. | .. |
---|
410 | 408 | expire_at = idle_timestamp + rxrpc_closed_conn_expiry * HZ; |
---|
411 | 409 | |
---|
412 | 410 | _debug("reap CONN %d { u=%d,t=%ld }", |
---|
413 | | - conn->debug_id, atomic_read(&conn->usage), |
---|
| 411 | + conn->debug_id, refcount_read(&conn->ref), |
---|
414 | 412 | (long)expire_at - (long)now); |
---|
415 | 413 | |
---|
416 | 414 | if (time_before(now, expire_at)) { |
---|
.. | .. |
---|
423 | 421 | /* The usage count sits at 1 whilst the object is unused on the |
---|
424 | 422 | * list; we reduce that to 0 to make the object unavailable. |
---|
425 | 423 | */ |
---|
426 | | - if (atomic_cmpxchg(&conn->usage, 1, 0) != 1) |
---|
| 424 | + if (!refcount_dec_if_one(&conn->ref)) |
---|
427 | 425 | continue; |
---|
428 | 426 | trace_rxrpc_conn(conn->debug_id, rxrpc_conn_reap_service, 0, NULL); |
---|
429 | 427 | |
---|
.. | .. |
---|
447 | 445 | link); |
---|
448 | 446 | list_del_init(&conn->link); |
---|
449 | 447 | |
---|
450 | | - ASSERTCMP(atomic_read(&conn->usage), ==, 0); |
---|
| 448 | + ASSERTCMP(refcount_read(&conn->ref), ==, 0); |
---|
451 | 449 | rxrpc_kill_connection(conn); |
---|
452 | 450 | } |
---|
453 | 451 | |
---|
.. | .. |
---|
475 | 473 | write_lock(&rxnet->conn_lock); |
---|
476 | 474 | list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { |
---|
477 | 475 | pr_err("AF_RXRPC: Leaked conn %p {%d}\n", |
---|
478 | | - conn, atomic_read(&conn->usage)); |
---|
| 476 | + conn, refcount_read(&conn->ref)); |
---|
479 | 477 | leak = true; |
---|
480 | 478 | } |
---|
481 | 479 | write_unlock(&rxnet->conn_lock); |
---|