18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* RxRPC virtual connection handler, common bits. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/slab.h> 128c2ecf20Sopenharmony_ci#include <linux/net.h> 138c2ecf20Sopenharmony_ci#include <linux/skbuff.h> 148c2ecf20Sopenharmony_ci#include "ar-internal.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/* 178c2ecf20Sopenharmony_ci * Time till a connection expires after last use (in seconds). 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ciunsigned int __read_mostly rxrpc_connection_expiry = 10 * 60; 208c2ecf20Sopenharmony_ciunsigned int __read_mostly rxrpc_closed_conn_expiry = 10; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic void rxrpc_destroy_connection(struct rcu_head *); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistatic void rxrpc_connection_timer(struct timer_list *timer) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci struct rxrpc_connection *conn = 278c2ecf20Sopenharmony_ci container_of(timer, struct rxrpc_connection, timer); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci rxrpc_queue_conn(conn); 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* 338c2ecf20Sopenharmony_ci * allocate a new connection 348c2ecf20Sopenharmony_ci */ 358c2ecf20Sopenharmony_cistruct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp) 368c2ecf20Sopenharmony_ci{ 378c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci _enter(""); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci conn = kzalloc(sizeof(struct rxrpc_connection), gfp); 428c2ecf20Sopenharmony_ci if (conn) { 438c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&conn->cache_link); 448c2ecf20Sopenharmony_ci timer_setup(&conn->timer, &rxrpc_connection_timer, 0); 458c2ecf20Sopenharmony_ci INIT_WORK(&conn->processor, &rxrpc_process_connection); 468c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&conn->proc_link); 478c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&conn->link); 488c2ecf20Sopenharmony_ci skb_queue_head_init(&conn->rx_queue); 498c2ecf20Sopenharmony_ci conn->security = &rxrpc_no_security; 508c2ecf20Sopenharmony_ci spin_lock_init(&conn->state_lock); 518c2ecf20Sopenharmony_ci conn->debug_id = atomic_inc_return(&rxrpc_debug_id); 528c2ecf20Sopenharmony_ci conn->size_align = 4; 538c2ecf20Sopenharmony_ci conn->idle_timestamp = jiffies; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0); 578c2ecf20Sopenharmony_ci return conn; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* 618c2ecf20Sopenharmony_ci * Look up a connection in the cache by protocol parameters. 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * If successful, a pointer to the connection is returned, but no ref is taken. 648c2ecf20Sopenharmony_ci * NULL is returned if there is no match. 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * When searching for a service call, if we find a peer but no connection, we 678c2ecf20Sopenharmony_ci * return that through *_peer in case we need to create a new service call. 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * The caller must be holding the RCU read lock. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_cistruct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local, 728c2ecf20Sopenharmony_ci struct sk_buff *skb, 738c2ecf20Sopenharmony_ci struct rxrpc_peer **_peer) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 768c2ecf20Sopenharmony_ci struct rxrpc_conn_proto k; 778c2ecf20Sopenharmony_ci struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 788c2ecf20Sopenharmony_ci struct sockaddr_rxrpc srx; 798c2ecf20Sopenharmony_ci struct rxrpc_peer *peer; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci _enter(",%x", sp->hdr.cid & RXRPC_CIDMASK); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (rxrpc_extract_addr_from_skb(&srx, skb) < 0) 848c2ecf20Sopenharmony_ci goto not_found; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci if (srx.transport.family != local->srx.transport.family && 878c2ecf20Sopenharmony_ci (srx.transport.family == AF_INET && 888c2ecf20Sopenharmony_ci local->srx.transport.family != AF_INET6)) { 898c2ecf20Sopenharmony_ci pr_warn_ratelimited("AF_RXRPC: Protocol mismatch %u not %u\n", 908c2ecf20Sopenharmony_ci srx.transport.family, 918c2ecf20Sopenharmony_ci local->srx.transport.family); 928c2ecf20Sopenharmony_ci goto not_found; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci k.epoch = sp->hdr.epoch; 968c2ecf20Sopenharmony_ci k.cid = sp->hdr.cid & RXRPC_CIDMASK; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci if (rxrpc_to_server(sp)) { 998c2ecf20Sopenharmony_ci /* We need to look up service connections by the full protocol 1008c2ecf20Sopenharmony_ci * parameter set. We look up the peer first as an intermediate 1018c2ecf20Sopenharmony_ci * step and then the connection from the peer's tree. 1028c2ecf20Sopenharmony_ci */ 1038c2ecf20Sopenharmony_ci peer = rxrpc_lookup_peer_rcu(local, &srx); 1048c2ecf20Sopenharmony_ci if (!peer) 1058c2ecf20Sopenharmony_ci goto not_found; 1068c2ecf20Sopenharmony_ci *_peer = peer; 1078c2ecf20Sopenharmony_ci conn = rxrpc_find_service_conn_rcu(peer, skb); 1088c2ecf20Sopenharmony_ci if (!conn || refcount_read(&conn->ref) == 0) 1098c2ecf20Sopenharmony_ci goto not_found; 1108c2ecf20Sopenharmony_ci _leave(" = %p", conn); 1118c2ecf20Sopenharmony_ci return conn; 1128c2ecf20Sopenharmony_ci } else { 1138c2ecf20Sopenharmony_ci /* Look up client connections by connection ID alone as their 1148c2ecf20Sopenharmony_ci * IDs are unique for this machine. 1158c2ecf20Sopenharmony_ci */ 1168c2ecf20Sopenharmony_ci conn = idr_find(&rxrpc_client_conn_ids, 1178c2ecf20Sopenharmony_ci sp->hdr.cid >> RXRPC_CIDSHIFT); 1188c2ecf20Sopenharmony_ci if (!conn || refcount_read(&conn->ref) == 0) { 1198c2ecf20Sopenharmony_ci _debug("no conn"); 1208c2ecf20Sopenharmony_ci goto not_found; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (conn->proto.epoch != k.epoch || 1248c2ecf20Sopenharmony_ci conn->params.local != local) 1258c2ecf20Sopenharmony_ci goto not_found; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci peer = conn->params.peer; 1288c2ecf20Sopenharmony_ci switch (srx.transport.family) { 1298c2ecf20Sopenharmony_ci case AF_INET: 1308c2ecf20Sopenharmony_ci if (peer->srx.transport.sin.sin_port != 1318c2ecf20Sopenharmony_ci srx.transport.sin.sin_port || 1328c2ecf20Sopenharmony_ci peer->srx.transport.sin.sin_addr.s_addr != 1338c2ecf20Sopenharmony_ci srx.transport.sin.sin_addr.s_addr) 1348c2ecf20Sopenharmony_ci goto not_found; 1358c2ecf20Sopenharmony_ci break; 1368c2ecf20Sopenharmony_ci#ifdef CONFIG_AF_RXRPC_IPV6 1378c2ecf20Sopenharmony_ci case AF_INET6: 1388c2ecf20Sopenharmony_ci if (peer->srx.transport.sin6.sin6_port != 1398c2ecf20Sopenharmony_ci srx.transport.sin6.sin6_port || 1408c2ecf20Sopenharmony_ci memcmp(&peer->srx.transport.sin6.sin6_addr, 1418c2ecf20Sopenharmony_ci &srx.transport.sin6.sin6_addr, 1428c2ecf20Sopenharmony_ci sizeof(struct in6_addr)) != 0) 1438c2ecf20Sopenharmony_ci goto not_found; 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci#endif 1468c2ecf20Sopenharmony_ci default: 1478c2ecf20Sopenharmony_ci BUG(); 1488c2ecf20Sopenharmony_ci } 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci _leave(" = %p", conn); 1518c2ecf20Sopenharmony_ci return conn; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cinot_found: 1558c2ecf20Sopenharmony_ci _leave(" = NULL"); 1568c2ecf20Sopenharmony_ci return NULL; 1578c2ecf20Sopenharmony_ci} 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci/* 1608c2ecf20Sopenharmony_ci * Disconnect a call and clear any channel it occupies when that call 1618c2ecf20Sopenharmony_ci * terminates. The caller must hold the channel_lock and must release the 1628c2ecf20Sopenharmony_ci * call's ref on the connection. 1638c2ecf20Sopenharmony_ci */ 1648c2ecf20Sopenharmony_civoid __rxrpc_disconnect_call(struct rxrpc_connection *conn, 1658c2ecf20Sopenharmony_ci struct rxrpc_call *call) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct rxrpc_channel *chan = 1688c2ecf20Sopenharmony_ci &conn->channels[call->cid & RXRPC_CHANNELMASK]; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci _enter("%d,%x", conn->debug_id, call->cid); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (rcu_access_pointer(chan->call) == call) { 1738c2ecf20Sopenharmony_ci /* Save the result of the call so that we can repeat it if necessary 1748c2ecf20Sopenharmony_ci * through the channel, whilst disposing of the actual call record. 1758c2ecf20Sopenharmony_ci */ 1768c2ecf20Sopenharmony_ci trace_rxrpc_disconnect_call(call); 1778c2ecf20Sopenharmony_ci switch (call->completion) { 1788c2ecf20Sopenharmony_ci case RXRPC_CALL_SUCCEEDED: 1798c2ecf20Sopenharmony_ci chan->last_seq = call->rx_hard_ack; 1808c2ecf20Sopenharmony_ci chan->last_type = RXRPC_PACKET_TYPE_ACK; 1818c2ecf20Sopenharmony_ci break; 1828c2ecf20Sopenharmony_ci case RXRPC_CALL_LOCALLY_ABORTED: 1838c2ecf20Sopenharmony_ci chan->last_abort = call->abort_code; 1848c2ecf20Sopenharmony_ci chan->last_type = RXRPC_PACKET_TYPE_ABORT; 1858c2ecf20Sopenharmony_ci break; 1868c2ecf20Sopenharmony_ci default: 1878c2ecf20Sopenharmony_ci chan->last_abort = RX_CALL_DEAD; 1888c2ecf20Sopenharmony_ci chan->last_type = RXRPC_PACKET_TYPE_ABORT; 1898c2ecf20Sopenharmony_ci break; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* Sync with rxrpc_conn_retransmit(). */ 1938c2ecf20Sopenharmony_ci smp_wmb(); 1948c2ecf20Sopenharmony_ci chan->last_call = chan->call_id; 1958c2ecf20Sopenharmony_ci chan->call_id = chan->call_counter; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci rcu_assign_pointer(chan->call, NULL); 1988c2ecf20Sopenharmony_ci } 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci _leave(""); 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* 2048c2ecf20Sopenharmony_ci * Disconnect a call and clear any channel it occupies when that call 2058c2ecf20Sopenharmony_ci * terminates. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_civoid rxrpc_disconnect_call(struct rxrpc_call *call) 2088c2ecf20Sopenharmony_ci{ 2098c2ecf20Sopenharmony_ci struct rxrpc_connection *conn = call->conn; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci call->peer->cong_cwnd = call->cong_cwnd; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (!hlist_unhashed(&call->error_link)) { 2148c2ecf20Sopenharmony_ci spin_lock_bh(&call->peer->lock); 2158c2ecf20Sopenharmony_ci hlist_del_rcu(&call->error_link); 2168c2ecf20Sopenharmony_ci spin_unlock_bh(&call->peer->lock); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (rxrpc_is_client_call(call)) 2208c2ecf20Sopenharmony_ci return rxrpc_disconnect_client_call(conn->bundle, call); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci spin_lock(&conn->bundle->channel_lock); 2238c2ecf20Sopenharmony_ci __rxrpc_disconnect_call(conn, call); 2248c2ecf20Sopenharmony_ci spin_unlock(&conn->bundle->channel_lock); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); 2278c2ecf20Sopenharmony_ci conn->idle_timestamp = jiffies; 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci/* 2318c2ecf20Sopenharmony_ci * Kill off a connection. 2328c2ecf20Sopenharmony_ci */ 2338c2ecf20Sopenharmony_civoid rxrpc_kill_connection(struct rxrpc_connection *conn) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = conn->params.local->rxnet; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci ASSERT(!rcu_access_pointer(conn->channels[0].call) && 2388c2ecf20Sopenharmony_ci !rcu_access_pointer(conn->channels[1].call) && 2398c2ecf20Sopenharmony_ci !rcu_access_pointer(conn->channels[2].call) && 2408c2ecf20Sopenharmony_ci !rcu_access_pointer(conn->channels[3].call)); 2418c2ecf20Sopenharmony_ci ASSERT(list_empty(&conn->cache_link)); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci write_lock(&rxnet->conn_lock); 2448c2ecf20Sopenharmony_ci list_del_init(&conn->proc_link); 2458c2ecf20Sopenharmony_ci write_unlock(&rxnet->conn_lock); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Drain the Rx queue. Note that even though we've unpublished, an 2488c2ecf20Sopenharmony_ci * incoming packet could still be being added to our Rx queue, so we 2498c2ecf20Sopenharmony_ci * will need to drain it again in the RCU cleanup handler. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci rxrpc_purge_queue(&conn->rx_queue); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* Leave final destruction to RCU. The connection processor work item 2548c2ecf20Sopenharmony_ci * must carry a ref on the connection to prevent us getting here whilst 2558c2ecf20Sopenharmony_ci * it is queued or running. 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci call_rcu(&conn->rcu, rxrpc_destroy_connection); 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci/* 2618c2ecf20Sopenharmony_ci * Queue a connection's work processor, getting a ref to pass to the work 2628c2ecf20Sopenharmony_ci * queue. 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_cibool rxrpc_queue_conn(struct rxrpc_connection *conn) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 2678c2ecf20Sopenharmony_ci int r; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (!__refcount_inc_not_zero(&conn->ref, &r)) 2708c2ecf20Sopenharmony_ci return false; 2718c2ecf20Sopenharmony_ci if (rxrpc_queue_work(&conn->processor)) 2728c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_queued, r + 1, here); 2738c2ecf20Sopenharmony_ci else 2748c2ecf20Sopenharmony_ci rxrpc_put_connection(conn); 2758c2ecf20Sopenharmony_ci return true; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* 2798c2ecf20Sopenharmony_ci * Note the re-emergence of a connection. 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_civoid rxrpc_see_connection(struct rxrpc_connection *conn) 2828c2ecf20Sopenharmony_ci{ 2838c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 2848c2ecf20Sopenharmony_ci if (conn) { 2858c2ecf20Sopenharmony_ci int n = refcount_read(&conn->ref); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_seen, n, here); 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci/* 2928c2ecf20Sopenharmony_ci * Get a ref on a connection. 2938c2ecf20Sopenharmony_ci */ 2948c2ecf20Sopenharmony_cistruct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *conn) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 2978c2ecf20Sopenharmony_ci int r; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci __refcount_inc(&conn->ref, &r); 3008c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r, here); 3018c2ecf20Sopenharmony_ci return conn; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci/* 3058c2ecf20Sopenharmony_ci * Try to get a ref on a connection. 3068c2ecf20Sopenharmony_ci */ 3078c2ecf20Sopenharmony_cistruct rxrpc_connection * 3088c2ecf20Sopenharmony_cirxrpc_get_connection_maybe(struct rxrpc_connection *conn) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 3118c2ecf20Sopenharmony_ci int r; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (conn) { 3148c2ecf20Sopenharmony_ci if (__refcount_inc_not_zero(&conn->ref, &r)) 3158c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_got, r + 1, here); 3168c2ecf20Sopenharmony_ci else 3178c2ecf20Sopenharmony_ci conn = NULL; 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci return conn; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci/* 3238c2ecf20Sopenharmony_ci * Set the service connection reap timer. 3248c2ecf20Sopenharmony_ci */ 3258c2ecf20Sopenharmony_cistatic void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet, 3268c2ecf20Sopenharmony_ci unsigned long reap_at) 3278c2ecf20Sopenharmony_ci{ 3288c2ecf20Sopenharmony_ci if (rxnet->live) 3298c2ecf20Sopenharmony_ci timer_reduce(&rxnet->service_conn_reap_timer, reap_at); 3308c2ecf20Sopenharmony_ci} 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci/* 3338c2ecf20Sopenharmony_ci * Release a service connection 3348c2ecf20Sopenharmony_ci */ 3358c2ecf20Sopenharmony_civoid rxrpc_put_service_conn(struct rxrpc_connection *conn) 3368c2ecf20Sopenharmony_ci{ 3378c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 3388c2ecf20Sopenharmony_ci unsigned int debug_id = conn->debug_id; 3398c2ecf20Sopenharmony_ci int r; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci __refcount_dec(&conn->ref, &r); 3428c2ecf20Sopenharmony_ci trace_rxrpc_conn(debug_id, rxrpc_conn_put_service, r - 1, here); 3438c2ecf20Sopenharmony_ci if (r - 1 == 1) 3448c2ecf20Sopenharmony_ci rxrpc_set_service_reap_timer(conn->params.local->rxnet, 3458c2ecf20Sopenharmony_ci jiffies + rxrpc_connection_expiry); 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci/* 3498c2ecf20Sopenharmony_ci * destroy a virtual connection 3508c2ecf20Sopenharmony_ci */ 3518c2ecf20Sopenharmony_cistatic void rxrpc_destroy_connection(struct rcu_head *rcu) 3528c2ecf20Sopenharmony_ci{ 3538c2ecf20Sopenharmony_ci struct rxrpc_connection *conn = 3548c2ecf20Sopenharmony_ci container_of(rcu, struct rxrpc_connection, rcu); 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci _enter("{%d,u=%d}", conn->debug_id, refcount_read(&conn->ref)); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci ASSERTCMP(refcount_read(&conn->ref), ==, 0); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci _net("DESTROY CONN %d", conn->debug_id); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci del_timer_sync(&conn->timer); 3638c2ecf20Sopenharmony_ci rxrpc_purge_queue(&conn->rx_queue); 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci conn->security->clear(conn); 3668c2ecf20Sopenharmony_ci key_put(conn->params.key); 3678c2ecf20Sopenharmony_ci key_put(conn->server_key); 3688c2ecf20Sopenharmony_ci rxrpc_put_bundle(conn->bundle); 3698c2ecf20Sopenharmony_ci rxrpc_put_peer(conn->params.peer); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&conn->params.local->rxnet->nr_conns)) 3728c2ecf20Sopenharmony_ci wake_up_var(&conn->params.local->rxnet->nr_conns); 3738c2ecf20Sopenharmony_ci rxrpc_put_local(conn->params.local); 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci kfree(conn); 3768c2ecf20Sopenharmony_ci _leave(""); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci/* 3808c2ecf20Sopenharmony_ci * reap dead service connections 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_civoid rxrpc_service_connection_reaper(struct work_struct *work) 3838c2ecf20Sopenharmony_ci{ 3848c2ecf20Sopenharmony_ci struct rxrpc_connection *conn, *_p; 3858c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = 3868c2ecf20Sopenharmony_ci container_of(work, struct rxrpc_net, service_conn_reaper); 3878c2ecf20Sopenharmony_ci unsigned long expire_at, earliest, idle_timestamp, now; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci LIST_HEAD(graveyard); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci _enter(""); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci now = jiffies; 3948c2ecf20Sopenharmony_ci earliest = now + MAX_JIFFY_OFFSET; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci write_lock(&rxnet->conn_lock); 3978c2ecf20Sopenharmony_ci list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { 3988c2ecf20Sopenharmony_ci ASSERTCMP(refcount_read(&conn->ref), >, 0); 3998c2ecf20Sopenharmony_ci if (likely(refcount_read(&conn->ref) > 1)) 4008c2ecf20Sopenharmony_ci continue; 4018c2ecf20Sopenharmony_ci if (conn->state == RXRPC_CONN_SERVICE_PREALLOC) 4028c2ecf20Sopenharmony_ci continue; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci if (rxnet->live && !conn->params.local->dead) { 4058c2ecf20Sopenharmony_ci idle_timestamp = READ_ONCE(conn->idle_timestamp); 4068c2ecf20Sopenharmony_ci expire_at = idle_timestamp + rxrpc_connection_expiry * HZ; 4078c2ecf20Sopenharmony_ci if (conn->params.local->service_closed) 4088c2ecf20Sopenharmony_ci expire_at = idle_timestamp + rxrpc_closed_conn_expiry * HZ; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci _debug("reap CONN %d { u=%d,t=%ld }", 4118c2ecf20Sopenharmony_ci conn->debug_id, refcount_read(&conn->ref), 4128c2ecf20Sopenharmony_ci (long)expire_at - (long)now); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci if (time_before(now, expire_at)) { 4158c2ecf20Sopenharmony_ci if (time_before(expire_at, earliest)) 4168c2ecf20Sopenharmony_ci earliest = expire_at; 4178c2ecf20Sopenharmony_ci continue; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* The usage count sits at 1 whilst the object is unused on the 4228c2ecf20Sopenharmony_ci * list; we reduce that to 0 to make the object unavailable. 4238c2ecf20Sopenharmony_ci */ 4248c2ecf20Sopenharmony_ci if (!refcount_dec_if_one(&conn->ref)) 4258c2ecf20Sopenharmony_ci continue; 4268c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_reap_service, 0, NULL); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (rxrpc_conn_is_client(conn)) 4298c2ecf20Sopenharmony_ci BUG(); 4308c2ecf20Sopenharmony_ci else 4318c2ecf20Sopenharmony_ci rxrpc_unpublish_service_conn(conn); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci list_move_tail(&conn->link, &graveyard); 4348c2ecf20Sopenharmony_ci } 4358c2ecf20Sopenharmony_ci write_unlock(&rxnet->conn_lock); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci if (earliest != now + MAX_JIFFY_OFFSET) { 4388c2ecf20Sopenharmony_ci _debug("reschedule reaper %ld", (long)earliest - (long)now); 4398c2ecf20Sopenharmony_ci ASSERT(time_after(earliest, now)); 4408c2ecf20Sopenharmony_ci rxrpc_set_service_reap_timer(rxnet, earliest); 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci while (!list_empty(&graveyard)) { 4448c2ecf20Sopenharmony_ci conn = list_entry(graveyard.next, struct rxrpc_connection, 4458c2ecf20Sopenharmony_ci link); 4468c2ecf20Sopenharmony_ci list_del_init(&conn->link); 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci ASSERTCMP(refcount_read(&conn->ref), ==, 0); 4498c2ecf20Sopenharmony_ci rxrpc_kill_connection(conn); 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci _leave(""); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci/* 4568c2ecf20Sopenharmony_ci * preemptively destroy all the service connection records rather than 4578c2ecf20Sopenharmony_ci * waiting for them to time out 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_civoid rxrpc_destroy_all_connections(struct rxrpc_net *rxnet) 4608c2ecf20Sopenharmony_ci{ 4618c2ecf20Sopenharmony_ci struct rxrpc_connection *conn, *_p; 4628c2ecf20Sopenharmony_ci bool leak = false; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci _enter(""); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci atomic_dec(&rxnet->nr_conns); 4678c2ecf20Sopenharmony_ci rxrpc_destroy_all_client_connections(rxnet); 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci del_timer_sync(&rxnet->service_conn_reap_timer); 4708c2ecf20Sopenharmony_ci rxrpc_queue_work(&rxnet->service_conn_reaper); 4718c2ecf20Sopenharmony_ci flush_workqueue(rxrpc_workqueue); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci write_lock(&rxnet->conn_lock); 4748c2ecf20Sopenharmony_ci list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) { 4758c2ecf20Sopenharmony_ci pr_err("AF_RXRPC: Leaked conn %p {%d}\n", 4768c2ecf20Sopenharmony_ci conn, refcount_read(&conn->ref)); 4778c2ecf20Sopenharmony_ci leak = true; 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci write_unlock(&rxnet->conn_lock); 4808c2ecf20Sopenharmony_ci BUG_ON(leak); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci ASSERT(list_empty(&rxnet->conn_proc_list)); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* We need to wait for the connections to be destroyed by RCU as they 4858c2ecf20Sopenharmony_ci * pin things that we still need to get rid of. 4868c2ecf20Sopenharmony_ci */ 4878c2ecf20Sopenharmony_ci wait_var_event(&rxnet->nr_conns, !atomic_read(&rxnet->nr_conns)); 4888c2ecf20Sopenharmony_ci _leave(""); 4898c2ecf20Sopenharmony_ci} 490