| .. | .. |
|---|
| 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); |
|---|