18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* Client connection-specific management code. 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2016, 2020 Red Hat, Inc. All Rights Reserved. 58c2ecf20Sopenharmony_ci * Written by David Howells (dhowells@redhat.com) 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Client connections need to be cached for a little while after they've made a 88c2ecf20Sopenharmony_ci * call so as to handle retransmitted DATA packets in case the server didn't 98c2ecf20Sopenharmony_ci * receive the final ACK or terminating ABORT we sent it. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * There are flags of relevance to the cache: 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * (2) DONT_REUSE - The connection should be discarded as soon as possible and 148c2ecf20Sopenharmony_ci * should not be reused. This is set when an exclusive connection is used 158c2ecf20Sopenharmony_ci * or a call ID counter overflows. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * The caching state may only be changed if the cache lock is held. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * There are two idle client connection expiry durations. If the total number 208c2ecf20Sopenharmony_ci * of connections is below the reap threshold, we use the normal duration; if 218c2ecf20Sopenharmony_ci * it's above, we use the fast duration. 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/slab.h> 278c2ecf20Sopenharmony_ci#include <linux/idr.h> 288c2ecf20Sopenharmony_ci#include <linux/timer.h> 298c2ecf20Sopenharmony_ci#include <linux/sched/signal.h> 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#include "ar-internal.h" 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci__read_mostly unsigned int rxrpc_reap_client_connections = 900; 348c2ecf20Sopenharmony_ci__read_mostly unsigned long rxrpc_conn_idle_client_expiry = 2 * 60 * HZ; 358c2ecf20Sopenharmony_ci__read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * We use machine-unique IDs for our client connections. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ciDEFINE_IDR(rxrpc_client_conn_ids); 418c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(rxrpc_conn_id_lock); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * Get a connection ID and epoch for a client connection from the global pool. 478c2ecf20Sopenharmony_ci * The connection struct pointer is then recorded in the idr radix tree. The 488c2ecf20Sopenharmony_ci * epoch doesn't change until the client is rebooted (or, at least, unless the 498c2ecf20Sopenharmony_ci * module is unloaded). 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_cistatic int rxrpc_get_client_connection_id(struct rxrpc_connection *conn, 528c2ecf20Sopenharmony_ci gfp_t gfp) 538c2ecf20Sopenharmony_ci{ 548c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = conn->params.local->rxnet; 558c2ecf20Sopenharmony_ci int id; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci _enter(""); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci idr_preload(gfp); 608c2ecf20Sopenharmony_ci spin_lock(&rxrpc_conn_id_lock); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn, 638c2ecf20Sopenharmony_ci 1, 0x40000000, GFP_NOWAIT); 648c2ecf20Sopenharmony_ci if (id < 0) 658c2ecf20Sopenharmony_ci goto error; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci spin_unlock(&rxrpc_conn_id_lock); 688c2ecf20Sopenharmony_ci idr_preload_end(); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci conn->proto.epoch = rxnet->epoch; 718c2ecf20Sopenharmony_ci conn->proto.cid = id << RXRPC_CIDSHIFT; 728c2ecf20Sopenharmony_ci set_bit(RXRPC_CONN_HAS_IDR, &conn->flags); 738c2ecf20Sopenharmony_ci _leave(" [CID %x]", conn->proto.cid); 748c2ecf20Sopenharmony_ci return 0; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cierror: 778c2ecf20Sopenharmony_ci spin_unlock(&rxrpc_conn_id_lock); 788c2ecf20Sopenharmony_ci idr_preload_end(); 798c2ecf20Sopenharmony_ci _leave(" = %d", id); 808c2ecf20Sopenharmony_ci return id; 818c2ecf20Sopenharmony_ci} 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * Release a connection ID for a client connection from the global pool. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_cistatic void rxrpc_put_client_connection_id(struct rxrpc_connection *conn) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CONN_HAS_IDR, &conn->flags)) { 898c2ecf20Sopenharmony_ci spin_lock(&rxrpc_conn_id_lock); 908c2ecf20Sopenharmony_ci idr_remove(&rxrpc_client_conn_ids, 918c2ecf20Sopenharmony_ci conn->proto.cid >> RXRPC_CIDSHIFT); 928c2ecf20Sopenharmony_ci spin_unlock(&rxrpc_conn_id_lock); 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * Destroy the client connection ID tree. 988c2ecf20Sopenharmony_ci */ 998c2ecf20Sopenharmony_civoid rxrpc_destroy_client_conn_ids(void) 1008c2ecf20Sopenharmony_ci{ 1018c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 1028c2ecf20Sopenharmony_ci int id; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci if (!idr_is_empty(&rxrpc_client_conn_ids)) { 1058c2ecf20Sopenharmony_ci idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) { 1068c2ecf20Sopenharmony_ci pr_err("AF_RXRPC: Leaked client conn %p {%d}\n", 1078c2ecf20Sopenharmony_ci conn, refcount_read(&conn->ref)); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci BUG(); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci idr_destroy(&rxrpc_client_conn_ids); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* 1168c2ecf20Sopenharmony_ci * Allocate a connection bundle. 1178c2ecf20Sopenharmony_ci */ 1188c2ecf20Sopenharmony_cistatic struct rxrpc_bundle *rxrpc_alloc_bundle(struct rxrpc_conn_parameters *cp, 1198c2ecf20Sopenharmony_ci gfp_t gfp) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci bundle = kzalloc(sizeof(*bundle), gfp); 1248c2ecf20Sopenharmony_ci if (bundle) { 1258c2ecf20Sopenharmony_ci bundle->params = *cp; 1268c2ecf20Sopenharmony_ci rxrpc_get_peer(bundle->params.peer); 1278c2ecf20Sopenharmony_ci refcount_set(&bundle->ref, 1); 1288c2ecf20Sopenharmony_ci atomic_set(&bundle->active, 1); 1298c2ecf20Sopenharmony_ci spin_lock_init(&bundle->channel_lock); 1308c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&bundle->waiting_calls); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci return bundle; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistruct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *bundle) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci refcount_inc(&bundle->ref); 1388c2ecf20Sopenharmony_ci return bundle; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic void rxrpc_free_bundle(struct rxrpc_bundle *bundle) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci rxrpc_put_peer(bundle->params.peer); 1448c2ecf20Sopenharmony_ci kfree(bundle); 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_civoid rxrpc_put_bundle(struct rxrpc_bundle *bundle) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci unsigned int d = bundle->debug_id; 1508c2ecf20Sopenharmony_ci bool dead; 1518c2ecf20Sopenharmony_ci int r; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci dead = __refcount_dec_and_test(&bundle->ref, &r); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci _debug("PUT B=%x %d", d, r - 1); 1568c2ecf20Sopenharmony_ci if (dead) 1578c2ecf20Sopenharmony_ci rxrpc_free_bundle(bundle); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci/* 1618c2ecf20Sopenharmony_ci * Allocate a client connection. 1628c2ecf20Sopenharmony_ci */ 1638c2ecf20Sopenharmony_cistatic struct rxrpc_connection * 1648c2ecf20Sopenharmony_cirxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 1678c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = bundle->params.local->rxnet; 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci _enter(""); 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci conn = rxrpc_alloc_connection(gfp); 1738c2ecf20Sopenharmony_ci if (!conn) { 1748c2ecf20Sopenharmony_ci _leave(" = -ENOMEM"); 1758c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci refcount_set(&conn->ref, 1); 1798c2ecf20Sopenharmony_ci conn->bundle = bundle; 1808c2ecf20Sopenharmony_ci conn->params = bundle->params; 1818c2ecf20Sopenharmony_ci conn->out_clientflag = RXRPC_CLIENT_INITIATED; 1828c2ecf20Sopenharmony_ci conn->state = RXRPC_CONN_CLIENT; 1838c2ecf20Sopenharmony_ci conn->service_id = conn->params.service_id; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci ret = rxrpc_get_client_connection_id(conn, gfp); 1868c2ecf20Sopenharmony_ci if (ret < 0) 1878c2ecf20Sopenharmony_ci goto error_0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci ret = rxrpc_init_client_conn_security(conn); 1908c2ecf20Sopenharmony_ci if (ret < 0) 1918c2ecf20Sopenharmony_ci goto error_1; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci ret = conn->security->prime_packet_security(conn); 1948c2ecf20Sopenharmony_ci if (ret < 0) 1958c2ecf20Sopenharmony_ci goto error_2; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci atomic_inc(&rxnet->nr_conns); 1988c2ecf20Sopenharmony_ci write_lock(&rxnet->conn_lock); 1998c2ecf20Sopenharmony_ci list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); 2008c2ecf20Sopenharmony_ci write_unlock(&rxnet->conn_lock); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci rxrpc_get_bundle(bundle); 2038c2ecf20Sopenharmony_ci rxrpc_get_peer(conn->params.peer); 2048c2ecf20Sopenharmony_ci rxrpc_get_local(conn->params.local); 2058c2ecf20Sopenharmony_ci key_get(conn->params.key); 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci trace_rxrpc_conn(conn->debug_id, rxrpc_conn_new_client, 2088c2ecf20Sopenharmony_ci refcount_read(&conn->ref), 2098c2ecf20Sopenharmony_ci __builtin_return_address(0)); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci atomic_inc(&rxnet->nr_client_conns); 2128c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, -1, rxrpc_client_alloc); 2138c2ecf20Sopenharmony_ci _leave(" = %p", conn); 2148c2ecf20Sopenharmony_ci return conn; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cierror_2: 2178c2ecf20Sopenharmony_ci conn->security->clear(conn); 2188c2ecf20Sopenharmony_cierror_1: 2198c2ecf20Sopenharmony_ci rxrpc_put_client_connection_id(conn); 2208c2ecf20Sopenharmony_cierror_0: 2218c2ecf20Sopenharmony_ci kfree(conn); 2228c2ecf20Sopenharmony_ci _leave(" = %d", ret); 2238c2ecf20Sopenharmony_ci return ERR_PTR(ret); 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci/* 2278c2ecf20Sopenharmony_ci * Determine if a connection may be reused. 2288c2ecf20Sopenharmony_ci */ 2298c2ecf20Sopenharmony_cistatic bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet; 2328c2ecf20Sopenharmony_ci int id_cursor, id, distance, limit; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci if (!conn) 2358c2ecf20Sopenharmony_ci goto dont_reuse; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci rxnet = conn->params.local->rxnet; 2388c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CONN_DONT_REUSE, &conn->flags)) 2398c2ecf20Sopenharmony_ci goto dont_reuse; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci if (conn->state != RXRPC_CONN_CLIENT || 2428c2ecf20Sopenharmony_ci conn->proto.epoch != rxnet->epoch) 2438c2ecf20Sopenharmony_ci goto mark_dont_reuse; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci /* The IDR tree gets very expensive on memory if the connection IDs are 2468c2ecf20Sopenharmony_ci * widely scattered throughout the number space, so we shall want to 2478c2ecf20Sopenharmony_ci * kill off connections that, say, have an ID more than about four 2488c2ecf20Sopenharmony_ci * times the maximum number of client conns away from the current 2498c2ecf20Sopenharmony_ci * allocation point to try and keep the IDs concentrated. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci id_cursor = idr_get_cursor(&rxrpc_client_conn_ids); 2528c2ecf20Sopenharmony_ci id = conn->proto.cid >> RXRPC_CIDSHIFT; 2538c2ecf20Sopenharmony_ci distance = id - id_cursor; 2548c2ecf20Sopenharmony_ci if (distance < 0) 2558c2ecf20Sopenharmony_ci distance = -distance; 2568c2ecf20Sopenharmony_ci limit = max_t(unsigned long, atomic_read(&rxnet->nr_conns) * 4, 1024); 2578c2ecf20Sopenharmony_ci if (distance > limit) 2588c2ecf20Sopenharmony_ci goto mark_dont_reuse; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return true; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cimark_dont_reuse: 2638c2ecf20Sopenharmony_ci set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags); 2648c2ecf20Sopenharmony_cidont_reuse: 2658c2ecf20Sopenharmony_ci return false; 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci/* 2698c2ecf20Sopenharmony_ci * Look up the conn bundle that matches the connection parameters, adding it if 2708c2ecf20Sopenharmony_ci * it doesn't yet exist. 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_cistatic struct rxrpc_bundle *rxrpc_look_up_bundle(struct rxrpc_conn_parameters *cp, 2738c2ecf20Sopenharmony_ci gfp_t gfp) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci static atomic_t rxrpc_bundle_id; 2768c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle, *candidate; 2778c2ecf20Sopenharmony_ci struct rxrpc_local *local = cp->local; 2788c2ecf20Sopenharmony_ci struct rb_node *p, **pp, *parent; 2798c2ecf20Sopenharmony_ci long diff; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci _enter("{%px,%x,%u,%u}", 2828c2ecf20Sopenharmony_ci cp->peer, key_serial(cp->key), cp->security_level, cp->upgrade); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (cp->exclusive) 2858c2ecf20Sopenharmony_ci return rxrpc_alloc_bundle(cp, gfp); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci /* First, see if the bundle is already there. */ 2888c2ecf20Sopenharmony_ci _debug("search 1"); 2898c2ecf20Sopenharmony_ci spin_lock(&local->client_bundles_lock); 2908c2ecf20Sopenharmony_ci p = local->client_bundles.rb_node; 2918c2ecf20Sopenharmony_ci while (p) { 2928c2ecf20Sopenharmony_ci bundle = rb_entry(p, struct rxrpc_bundle, local_node); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci#define cmp(X) ((long)bundle->params.X - (long)cp->X) 2958c2ecf20Sopenharmony_ci diff = (cmp(peer) ?: 2968c2ecf20Sopenharmony_ci cmp(key) ?: 2978c2ecf20Sopenharmony_ci cmp(security_level) ?: 2988c2ecf20Sopenharmony_ci cmp(upgrade)); 2998c2ecf20Sopenharmony_ci#undef cmp 3008c2ecf20Sopenharmony_ci if (diff < 0) 3018c2ecf20Sopenharmony_ci p = p->rb_left; 3028c2ecf20Sopenharmony_ci else if (diff > 0) 3038c2ecf20Sopenharmony_ci p = p->rb_right; 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci goto found_bundle; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci spin_unlock(&local->client_bundles_lock); 3088c2ecf20Sopenharmony_ci _debug("not found"); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci /* It wasn't. We need to add one. */ 3118c2ecf20Sopenharmony_ci candidate = rxrpc_alloc_bundle(cp, gfp); 3128c2ecf20Sopenharmony_ci if (!candidate) 3138c2ecf20Sopenharmony_ci return NULL; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci _debug("search 2"); 3168c2ecf20Sopenharmony_ci spin_lock(&local->client_bundles_lock); 3178c2ecf20Sopenharmony_ci pp = &local->client_bundles.rb_node; 3188c2ecf20Sopenharmony_ci parent = NULL; 3198c2ecf20Sopenharmony_ci while (*pp) { 3208c2ecf20Sopenharmony_ci parent = *pp; 3218c2ecf20Sopenharmony_ci bundle = rb_entry(parent, struct rxrpc_bundle, local_node); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci#define cmp(X) ((long)bundle->params.X - (long)cp->X) 3248c2ecf20Sopenharmony_ci diff = (cmp(peer) ?: 3258c2ecf20Sopenharmony_ci cmp(key) ?: 3268c2ecf20Sopenharmony_ci cmp(security_level) ?: 3278c2ecf20Sopenharmony_ci cmp(upgrade)); 3288c2ecf20Sopenharmony_ci#undef cmp 3298c2ecf20Sopenharmony_ci if (diff < 0) 3308c2ecf20Sopenharmony_ci pp = &(*pp)->rb_left; 3318c2ecf20Sopenharmony_ci else if (diff > 0) 3328c2ecf20Sopenharmony_ci pp = &(*pp)->rb_right; 3338c2ecf20Sopenharmony_ci else 3348c2ecf20Sopenharmony_ci goto found_bundle_free; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci _debug("new bundle"); 3388c2ecf20Sopenharmony_ci candidate->debug_id = atomic_inc_return(&rxrpc_bundle_id); 3398c2ecf20Sopenharmony_ci rb_link_node(&candidate->local_node, parent, pp); 3408c2ecf20Sopenharmony_ci rb_insert_color(&candidate->local_node, &local->client_bundles); 3418c2ecf20Sopenharmony_ci rxrpc_get_bundle(candidate); 3428c2ecf20Sopenharmony_ci spin_unlock(&local->client_bundles_lock); 3438c2ecf20Sopenharmony_ci _leave(" = %u [new]", candidate->debug_id); 3448c2ecf20Sopenharmony_ci return candidate; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cifound_bundle_free: 3478c2ecf20Sopenharmony_ci rxrpc_free_bundle(candidate); 3488c2ecf20Sopenharmony_cifound_bundle: 3498c2ecf20Sopenharmony_ci rxrpc_get_bundle(bundle); 3508c2ecf20Sopenharmony_ci atomic_inc(&bundle->active); 3518c2ecf20Sopenharmony_ci spin_unlock(&local->client_bundles_lock); 3528c2ecf20Sopenharmony_ci _leave(" = %u [found]", bundle->debug_id); 3538c2ecf20Sopenharmony_ci return bundle; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci/* 3578c2ecf20Sopenharmony_ci * Create or find a client bundle to use for a call. 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * If we return with a connection, the call will be on its waiting list. It's 3608c2ecf20Sopenharmony_ci * left to the caller to assign a channel and wake up the call. 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_cistatic struct rxrpc_bundle *rxrpc_prep_call(struct rxrpc_sock *rx, 3638c2ecf20Sopenharmony_ci struct rxrpc_call *call, 3648c2ecf20Sopenharmony_ci struct rxrpc_conn_parameters *cp, 3658c2ecf20Sopenharmony_ci struct sockaddr_rxrpc *srx, 3668c2ecf20Sopenharmony_ci gfp_t gfp) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci _enter("{%d,%lx},", call->debug_id, call->user_call_ID); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci cp->peer = rxrpc_lookup_peer(rx, cp->local, srx, gfp); 3738c2ecf20Sopenharmony_ci if (!cp->peer) 3748c2ecf20Sopenharmony_ci goto error; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci call->cong_cwnd = cp->peer->cong_cwnd; 3778c2ecf20Sopenharmony_ci if (call->cong_cwnd >= call->cong_ssthresh) 3788c2ecf20Sopenharmony_ci call->cong_mode = RXRPC_CALL_CONGEST_AVOIDANCE; 3798c2ecf20Sopenharmony_ci else 3808c2ecf20Sopenharmony_ci call->cong_mode = RXRPC_CALL_SLOW_START; 3818c2ecf20Sopenharmony_ci if (cp->upgrade) 3828c2ecf20Sopenharmony_ci __set_bit(RXRPC_CALL_UPGRADE, &call->flags); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci /* Find the client connection bundle. */ 3858c2ecf20Sopenharmony_ci bundle = rxrpc_look_up_bundle(cp, gfp); 3868c2ecf20Sopenharmony_ci if (!bundle) 3878c2ecf20Sopenharmony_ci goto error; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Get this call queued. Someone else may activate it whilst we're 3908c2ecf20Sopenharmony_ci * lining up a new connection, but that's fine. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 3938c2ecf20Sopenharmony_ci list_add_tail(&call->chan_wait_link, &bundle->waiting_calls); 3948c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci _leave(" = [B=%x]", bundle->debug_id); 3978c2ecf20Sopenharmony_ci return bundle; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cierror: 4008c2ecf20Sopenharmony_ci _leave(" = -ENOMEM"); 4018c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 4028c2ecf20Sopenharmony_ci} 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci/* 4058c2ecf20Sopenharmony_ci * Allocate a new connection and add it into a bundle. 4068c2ecf20Sopenharmony_ci */ 4078c2ecf20Sopenharmony_cistatic void rxrpc_add_conn_to_bundle(struct rxrpc_bundle *bundle, gfp_t gfp) 4088c2ecf20Sopenharmony_ci __releases(bundle->channel_lock) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci struct rxrpc_connection *candidate = NULL, *old = NULL; 4118c2ecf20Sopenharmony_ci bool conflict; 4128c2ecf20Sopenharmony_ci int i; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci _enter(""); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci conflict = bundle->alloc_conn; 4178c2ecf20Sopenharmony_ci if (!conflict) 4188c2ecf20Sopenharmony_ci bundle->alloc_conn = true; 4198c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 4208c2ecf20Sopenharmony_ci if (conflict) { 4218c2ecf20Sopenharmony_ci _leave(" [conf]"); 4228c2ecf20Sopenharmony_ci return; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci candidate = rxrpc_alloc_client_connection(bundle, gfp); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 4288c2ecf20Sopenharmony_ci bundle->alloc_conn = false; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci if (IS_ERR(candidate)) { 4318c2ecf20Sopenharmony_ci bundle->alloc_error = PTR_ERR(candidate); 4328c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 4338c2ecf20Sopenharmony_ci _leave(" [err %ld]", PTR_ERR(candidate)); 4348c2ecf20Sopenharmony_ci return; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci bundle->alloc_error = 0; 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) { 4408c2ecf20Sopenharmony_ci unsigned int shift = i * RXRPC_MAXCALLS; 4418c2ecf20Sopenharmony_ci int j; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci old = bundle->conns[i]; 4448c2ecf20Sopenharmony_ci if (!rxrpc_may_reuse_conn(old)) { 4458c2ecf20Sopenharmony_ci if (old) 4468c2ecf20Sopenharmony_ci trace_rxrpc_client(old, -1, rxrpc_client_replace); 4478c2ecf20Sopenharmony_ci candidate->bundle_shift = shift; 4488c2ecf20Sopenharmony_ci atomic_inc(&bundle->active); 4498c2ecf20Sopenharmony_ci bundle->conns[i] = candidate; 4508c2ecf20Sopenharmony_ci for (j = 0; j < RXRPC_MAXCALLS; j++) 4518c2ecf20Sopenharmony_ci set_bit(shift + j, &bundle->avail_chans); 4528c2ecf20Sopenharmony_ci candidate = NULL; 4538c2ecf20Sopenharmony_ci break; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci old = NULL; 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (candidate) { 4628c2ecf20Sopenharmony_ci _debug("discard C=%x", candidate->debug_id); 4638c2ecf20Sopenharmony_ci trace_rxrpc_client(candidate, -1, rxrpc_client_duplicate); 4648c2ecf20Sopenharmony_ci rxrpc_put_connection(candidate); 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci rxrpc_put_connection(old); 4688c2ecf20Sopenharmony_ci _leave(""); 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci/* 4728c2ecf20Sopenharmony_ci * Add a connection to a bundle if there are no usable connections or we have 4738c2ecf20Sopenharmony_ci * connections waiting for extra capacity. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_cistatic void rxrpc_maybe_add_conn(struct rxrpc_bundle *bundle, gfp_t gfp) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci struct rxrpc_call *call; 4788c2ecf20Sopenharmony_ci int i, usable; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci _enter(""); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* See if there are any usable connections. */ 4858c2ecf20Sopenharmony_ci usable = 0; 4868c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(bundle->conns); i++) 4878c2ecf20Sopenharmony_ci if (rxrpc_may_reuse_conn(bundle->conns[i])) 4888c2ecf20Sopenharmony_ci usable++; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci if (!usable && !list_empty(&bundle->waiting_calls)) { 4918c2ecf20Sopenharmony_ci call = list_first_entry(&bundle->waiting_calls, 4928c2ecf20Sopenharmony_ci struct rxrpc_call, chan_wait_link); 4938c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CALL_UPGRADE, &call->flags)) 4948c2ecf20Sopenharmony_ci bundle->try_upgrade = true; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci if (!usable) 4988c2ecf20Sopenharmony_ci goto alloc_conn; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (!bundle->avail_chans && 5018c2ecf20Sopenharmony_ci !bundle->try_upgrade && 5028c2ecf20Sopenharmony_ci !list_empty(&bundle->waiting_calls) && 5038c2ecf20Sopenharmony_ci usable < ARRAY_SIZE(bundle->conns)) 5048c2ecf20Sopenharmony_ci goto alloc_conn; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 5078c2ecf20Sopenharmony_ci _leave(""); 5088c2ecf20Sopenharmony_ci return; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cialloc_conn: 5118c2ecf20Sopenharmony_ci return rxrpc_add_conn_to_bundle(bundle, gfp); 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci/* 5158c2ecf20Sopenharmony_ci * Assign a channel to the call at the front of the queue and wake the call up. 5168c2ecf20Sopenharmony_ci * We don't increment the callNumber counter until this number has been exposed 5178c2ecf20Sopenharmony_ci * to the world. 5188c2ecf20Sopenharmony_ci */ 5198c2ecf20Sopenharmony_cistatic void rxrpc_activate_one_channel(struct rxrpc_connection *conn, 5208c2ecf20Sopenharmony_ci unsigned int channel) 5218c2ecf20Sopenharmony_ci{ 5228c2ecf20Sopenharmony_ci struct rxrpc_channel *chan = &conn->channels[channel]; 5238c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle = conn->bundle; 5248c2ecf20Sopenharmony_ci struct rxrpc_call *call = list_entry(bundle->waiting_calls.next, 5258c2ecf20Sopenharmony_ci struct rxrpc_call, chan_wait_link); 5268c2ecf20Sopenharmony_ci u32 call_id = chan->call_counter + 1; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci _enter("C=%x,%u", conn->debug_id, channel); 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_chan_activate); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Cancel the final ACK on the previous call if it hasn't been sent yet 5338c2ecf20Sopenharmony_ci * as the DATA packet will implicitly ACK it. 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci clear_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); 5368c2ecf20Sopenharmony_ci clear_bit(conn->bundle_shift + channel, &bundle->avail_chans); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci rxrpc_see_call(call); 5398c2ecf20Sopenharmony_ci list_del_init(&call->chan_wait_link); 5408c2ecf20Sopenharmony_ci call->peer = rxrpc_get_peer(conn->params.peer); 5418c2ecf20Sopenharmony_ci call->conn = rxrpc_get_connection(conn); 5428c2ecf20Sopenharmony_ci call->cid = conn->proto.cid | channel; 5438c2ecf20Sopenharmony_ci call->call_id = call_id; 5448c2ecf20Sopenharmony_ci call->security = conn->security; 5458c2ecf20Sopenharmony_ci call->security_ix = conn->security_ix; 5468c2ecf20Sopenharmony_ci call->service_id = conn->service_id; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci trace_rxrpc_connect_call(call); 5498c2ecf20Sopenharmony_ci _net("CONNECT call %08x:%08x as call %d on conn %d", 5508c2ecf20Sopenharmony_ci call->cid, call->call_id, call->debug_id, conn->debug_id); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci write_lock_bh(&call->state_lock); 5538c2ecf20Sopenharmony_ci call->state = RXRPC_CALL_CLIENT_SEND_REQUEST; 5548c2ecf20Sopenharmony_ci write_unlock_bh(&call->state_lock); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Paired with the read barrier in rxrpc_connect_call(). This orders 5578c2ecf20Sopenharmony_ci * cid and epoch in the connection wrt to call_id without the need to 5588c2ecf20Sopenharmony_ci * take the channel_lock. 5598c2ecf20Sopenharmony_ci * 5608c2ecf20Sopenharmony_ci * We provisionally assign a callNumber at this point, but we don't 5618c2ecf20Sopenharmony_ci * confirm it until the call is about to be exposed. 5628c2ecf20Sopenharmony_ci * 5638c2ecf20Sopenharmony_ci * TODO: Pair with a barrier in the data_ready handler when that looks 5648c2ecf20Sopenharmony_ci * at the call ID through a connection channel. 5658c2ecf20Sopenharmony_ci */ 5668c2ecf20Sopenharmony_ci smp_wmb(); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci chan->call_id = call_id; 5698c2ecf20Sopenharmony_ci chan->call_debug_id = call->debug_id; 5708c2ecf20Sopenharmony_ci rcu_assign_pointer(chan->call, call); 5718c2ecf20Sopenharmony_ci wake_up(&call->waitq); 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci/* 5758c2ecf20Sopenharmony_ci * Remove a connection from the idle list if it's on it. 5768c2ecf20Sopenharmony_ci */ 5778c2ecf20Sopenharmony_cistatic void rxrpc_unidle_conn(struct rxrpc_bundle *bundle, struct rxrpc_connection *conn) 5788c2ecf20Sopenharmony_ci{ 5798c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = bundle->params.local->rxnet; 5808c2ecf20Sopenharmony_ci bool drop_ref; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (!list_empty(&conn->cache_link)) { 5838c2ecf20Sopenharmony_ci drop_ref = false; 5848c2ecf20Sopenharmony_ci spin_lock(&rxnet->client_conn_cache_lock); 5858c2ecf20Sopenharmony_ci if (!list_empty(&conn->cache_link)) { 5868c2ecf20Sopenharmony_ci list_del_init(&conn->cache_link); 5878c2ecf20Sopenharmony_ci drop_ref = true; 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 5908c2ecf20Sopenharmony_ci if (drop_ref) 5918c2ecf20Sopenharmony_ci rxrpc_put_connection(conn); 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci/* 5968c2ecf20Sopenharmony_ci * Assign channels and callNumbers to waiting calls with channel_lock 5978c2ecf20Sopenharmony_ci * held by caller. 5988c2ecf20Sopenharmony_ci */ 5998c2ecf20Sopenharmony_cistatic void rxrpc_activate_channels_locked(struct rxrpc_bundle *bundle) 6008c2ecf20Sopenharmony_ci{ 6018c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 6028c2ecf20Sopenharmony_ci unsigned long avail, mask; 6038c2ecf20Sopenharmony_ci unsigned int channel, slot; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci if (bundle->try_upgrade) 6068c2ecf20Sopenharmony_ci mask = 1; 6078c2ecf20Sopenharmony_ci else 6088c2ecf20Sopenharmony_ci mask = ULONG_MAX; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci while (!list_empty(&bundle->waiting_calls)) { 6118c2ecf20Sopenharmony_ci avail = bundle->avail_chans & mask; 6128c2ecf20Sopenharmony_ci if (!avail) 6138c2ecf20Sopenharmony_ci break; 6148c2ecf20Sopenharmony_ci channel = __ffs(avail); 6158c2ecf20Sopenharmony_ci clear_bit(channel, &bundle->avail_chans); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci slot = channel / RXRPC_MAXCALLS; 6188c2ecf20Sopenharmony_ci conn = bundle->conns[slot]; 6198c2ecf20Sopenharmony_ci if (!conn) 6208c2ecf20Sopenharmony_ci break; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci if (bundle->try_upgrade) 6238c2ecf20Sopenharmony_ci set_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags); 6248c2ecf20Sopenharmony_ci rxrpc_unidle_conn(bundle, conn); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci channel &= (RXRPC_MAXCALLS - 1); 6278c2ecf20Sopenharmony_ci conn->act_chans |= 1 << channel; 6288c2ecf20Sopenharmony_ci rxrpc_activate_one_channel(conn, channel); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci} 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci/* 6338c2ecf20Sopenharmony_ci * Assign channels and callNumbers to waiting calls. 6348c2ecf20Sopenharmony_ci */ 6358c2ecf20Sopenharmony_cistatic void rxrpc_activate_channels(struct rxrpc_bundle *bundle) 6368c2ecf20Sopenharmony_ci{ 6378c2ecf20Sopenharmony_ci _enter("B=%x", bundle->debug_id); 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci trace_rxrpc_client(NULL, -1, rxrpc_client_activate_chans); 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (!bundle->avail_chans) 6428c2ecf20Sopenharmony_ci return; 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 6458c2ecf20Sopenharmony_ci rxrpc_activate_channels_locked(bundle); 6468c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 6478c2ecf20Sopenharmony_ci _leave(""); 6488c2ecf20Sopenharmony_ci} 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci/* 6518c2ecf20Sopenharmony_ci * Wait for a callNumber and a channel to be granted to a call. 6528c2ecf20Sopenharmony_ci */ 6538c2ecf20Sopenharmony_cistatic int rxrpc_wait_for_channel(struct rxrpc_bundle *bundle, 6548c2ecf20Sopenharmony_ci struct rxrpc_call *call, gfp_t gfp) 6558c2ecf20Sopenharmony_ci{ 6568c2ecf20Sopenharmony_ci DECLARE_WAITQUEUE(myself, current); 6578c2ecf20Sopenharmony_ci int ret = 0; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci _enter("%d", call->debug_id); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci if (!gfpflags_allow_blocking(gfp)) { 6628c2ecf20Sopenharmony_ci rxrpc_maybe_add_conn(bundle, gfp); 6638c2ecf20Sopenharmony_ci rxrpc_activate_channels(bundle); 6648c2ecf20Sopenharmony_ci ret = bundle->alloc_error ?: -EAGAIN; 6658c2ecf20Sopenharmony_ci goto out; 6668c2ecf20Sopenharmony_ci } 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci add_wait_queue_exclusive(&call->waitq, &myself); 6698c2ecf20Sopenharmony_ci for (;;) { 6708c2ecf20Sopenharmony_ci rxrpc_maybe_add_conn(bundle, gfp); 6718c2ecf20Sopenharmony_ci rxrpc_activate_channels(bundle); 6728c2ecf20Sopenharmony_ci ret = bundle->alloc_error; 6738c2ecf20Sopenharmony_ci if (ret < 0) 6748c2ecf20Sopenharmony_ci break; 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_ci switch (call->interruptibility) { 6778c2ecf20Sopenharmony_ci case RXRPC_INTERRUPTIBLE: 6788c2ecf20Sopenharmony_ci case RXRPC_PREINTERRUPTIBLE: 6798c2ecf20Sopenharmony_ci set_current_state(TASK_INTERRUPTIBLE); 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci case RXRPC_UNINTERRUPTIBLE: 6828c2ecf20Sopenharmony_ci default: 6838c2ecf20Sopenharmony_ci set_current_state(TASK_UNINTERRUPTIBLE); 6848c2ecf20Sopenharmony_ci break; 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci if (READ_ONCE(call->state) != RXRPC_CALL_CLIENT_AWAIT_CONN) 6878c2ecf20Sopenharmony_ci break; 6888c2ecf20Sopenharmony_ci if ((call->interruptibility == RXRPC_INTERRUPTIBLE || 6898c2ecf20Sopenharmony_ci call->interruptibility == RXRPC_PREINTERRUPTIBLE) && 6908c2ecf20Sopenharmony_ci signal_pending(current)) { 6918c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 6928c2ecf20Sopenharmony_ci break; 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci schedule(); 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci remove_wait_queue(&call->waitq, &myself); 6978c2ecf20Sopenharmony_ci __set_current_state(TASK_RUNNING); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ciout: 7008c2ecf20Sopenharmony_ci _leave(" = %d", ret); 7018c2ecf20Sopenharmony_ci return ret; 7028c2ecf20Sopenharmony_ci} 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci/* 7058c2ecf20Sopenharmony_ci * find a connection for a call 7068c2ecf20Sopenharmony_ci * - called in process context with IRQs enabled 7078c2ecf20Sopenharmony_ci */ 7088c2ecf20Sopenharmony_ciint rxrpc_connect_call(struct rxrpc_sock *rx, 7098c2ecf20Sopenharmony_ci struct rxrpc_call *call, 7108c2ecf20Sopenharmony_ci struct rxrpc_conn_parameters *cp, 7118c2ecf20Sopenharmony_ci struct sockaddr_rxrpc *srx, 7128c2ecf20Sopenharmony_ci gfp_t gfp) 7138c2ecf20Sopenharmony_ci{ 7148c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle; 7158c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = cp->local->rxnet; 7168c2ecf20Sopenharmony_ci int ret = 0; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci _enter("{%d,%lx},", call->debug_id, call->user_call_ID); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci rxrpc_discard_expired_client_conns(&rxnet->client_conn_reaper); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci bundle = rxrpc_prep_call(rx, call, cp, srx, gfp); 7238c2ecf20Sopenharmony_ci if (IS_ERR(bundle)) { 7248c2ecf20Sopenharmony_ci ret = PTR_ERR(bundle); 7258c2ecf20Sopenharmony_ci goto out; 7268c2ecf20Sopenharmony_ci } 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci if (call->state == RXRPC_CALL_CLIENT_AWAIT_CONN) { 7298c2ecf20Sopenharmony_ci ret = rxrpc_wait_for_channel(bundle, call, gfp); 7308c2ecf20Sopenharmony_ci if (ret < 0) 7318c2ecf20Sopenharmony_ci goto wait_failed; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cigranted_channel: 7358c2ecf20Sopenharmony_ci /* Paired with the write barrier in rxrpc_activate_one_channel(). */ 7368c2ecf20Sopenharmony_ci smp_rmb(); 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ciout_put_bundle: 7398c2ecf20Sopenharmony_ci rxrpc_deactivate_bundle(bundle); 7408c2ecf20Sopenharmony_ci rxrpc_put_bundle(bundle); 7418c2ecf20Sopenharmony_ciout: 7428c2ecf20Sopenharmony_ci _leave(" = %d", ret); 7438c2ecf20Sopenharmony_ci return ret; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ciwait_failed: 7468c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 7478c2ecf20Sopenharmony_ci list_del_init(&call->chan_wait_link); 7488c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 7498c2ecf20Sopenharmony_ci 7508c2ecf20Sopenharmony_ci if (call->state != RXRPC_CALL_CLIENT_AWAIT_CONN) { 7518c2ecf20Sopenharmony_ci ret = 0; 7528c2ecf20Sopenharmony_ci goto granted_channel; 7538c2ecf20Sopenharmony_ci } 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci trace_rxrpc_client(call->conn, ret, rxrpc_client_chan_wait_failed); 7568c2ecf20Sopenharmony_ci rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret); 7578c2ecf20Sopenharmony_ci rxrpc_disconnect_client_call(bundle, call); 7588c2ecf20Sopenharmony_ci goto out_put_bundle; 7598c2ecf20Sopenharmony_ci} 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ci/* 7628c2ecf20Sopenharmony_ci * Note that a call, and thus a connection, is about to be exposed to the 7638c2ecf20Sopenharmony_ci * world. 7648c2ecf20Sopenharmony_ci */ 7658c2ecf20Sopenharmony_civoid rxrpc_expose_client_call(struct rxrpc_call *call) 7668c2ecf20Sopenharmony_ci{ 7678c2ecf20Sopenharmony_ci unsigned int channel = call->cid & RXRPC_CHANNELMASK; 7688c2ecf20Sopenharmony_ci struct rxrpc_connection *conn = call->conn; 7698c2ecf20Sopenharmony_ci struct rxrpc_channel *chan = &conn->channels[channel]; 7708c2ecf20Sopenharmony_ci 7718c2ecf20Sopenharmony_ci if (!test_and_set_bit(RXRPC_CALL_EXPOSED, &call->flags)) { 7728c2ecf20Sopenharmony_ci /* Mark the call ID as being used. If the callNumber counter 7738c2ecf20Sopenharmony_ci * exceeds ~2 billion, we kill the connection after its 7748c2ecf20Sopenharmony_ci * outstanding calls have finished so that the counter doesn't 7758c2ecf20Sopenharmony_ci * wrap. 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci chan->call_counter++; 7788c2ecf20Sopenharmony_ci if (chan->call_counter >= INT_MAX) 7798c2ecf20Sopenharmony_ci set_bit(RXRPC_CONN_DONT_REUSE, &conn->flags); 7808c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_exposed); 7818c2ecf20Sopenharmony_ci } 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci/* 7858c2ecf20Sopenharmony_ci * Set the reap timer. 7868c2ecf20Sopenharmony_ci */ 7878c2ecf20Sopenharmony_cistatic void rxrpc_set_client_reap_timer(struct rxrpc_net *rxnet) 7888c2ecf20Sopenharmony_ci{ 7898c2ecf20Sopenharmony_ci if (!rxnet->kill_all_client_conns) { 7908c2ecf20Sopenharmony_ci unsigned long now = jiffies; 7918c2ecf20Sopenharmony_ci unsigned long reap_at = now + rxrpc_conn_idle_client_expiry; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci if (rxnet->live) 7948c2ecf20Sopenharmony_ci timer_reduce(&rxnet->client_conn_reap_timer, reap_at); 7958c2ecf20Sopenharmony_ci } 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/* 7998c2ecf20Sopenharmony_ci * Disconnect a client call. 8008c2ecf20Sopenharmony_ci */ 8018c2ecf20Sopenharmony_civoid rxrpc_disconnect_client_call(struct rxrpc_bundle *bundle, struct rxrpc_call *call) 8028c2ecf20Sopenharmony_ci{ 8038c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 8048c2ecf20Sopenharmony_ci struct rxrpc_channel *chan = NULL; 8058c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = bundle->params.local->rxnet; 8068c2ecf20Sopenharmony_ci unsigned int channel; 8078c2ecf20Sopenharmony_ci bool may_reuse; 8088c2ecf20Sopenharmony_ci u32 cid; 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci _enter("c=%x", call->debug_id); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 8138c2ecf20Sopenharmony_ci set_bit(RXRPC_CALL_DISCONNECTED, &call->flags); 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ci /* Calls that have never actually been assigned a channel can simply be 8168c2ecf20Sopenharmony_ci * discarded. 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_ci conn = call->conn; 8198c2ecf20Sopenharmony_ci if (!conn) { 8208c2ecf20Sopenharmony_ci _debug("call is waiting"); 8218c2ecf20Sopenharmony_ci ASSERTCMP(call->call_id, ==, 0); 8228c2ecf20Sopenharmony_ci ASSERT(!test_bit(RXRPC_CALL_EXPOSED, &call->flags)); 8238c2ecf20Sopenharmony_ci list_del_init(&call->chan_wait_link); 8248c2ecf20Sopenharmony_ci goto out; 8258c2ecf20Sopenharmony_ci } 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci cid = call->cid; 8288c2ecf20Sopenharmony_ci channel = cid & RXRPC_CHANNELMASK; 8298c2ecf20Sopenharmony_ci chan = &conn->channels[channel]; 8308c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_chan_disconnect); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (rcu_access_pointer(chan->call) != call) { 8338c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 8348c2ecf20Sopenharmony_ci BUG(); 8358c2ecf20Sopenharmony_ci } 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci may_reuse = rxrpc_may_reuse_conn(conn); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci /* If a client call was exposed to the world, we save the result for 8408c2ecf20Sopenharmony_ci * retransmission. 8418c2ecf20Sopenharmony_ci * 8428c2ecf20Sopenharmony_ci * We use a barrier here so that the call number and abort code can be 8438c2ecf20Sopenharmony_ci * read without needing to take a lock. 8448c2ecf20Sopenharmony_ci * 8458c2ecf20Sopenharmony_ci * TODO: Make the incoming packet handler check this and handle 8468c2ecf20Sopenharmony_ci * terminal retransmission without requiring access to the call. 8478c2ecf20Sopenharmony_ci */ 8488c2ecf20Sopenharmony_ci if (test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { 8498c2ecf20Sopenharmony_ci _debug("exposed %u,%u", call->call_id, call->abort_code); 8508c2ecf20Sopenharmony_ci __rxrpc_disconnect_call(conn, call); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci if (test_and_clear_bit(RXRPC_CONN_PROBING_FOR_UPGRADE, &conn->flags)) { 8538c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_to_active); 8548c2ecf20Sopenharmony_ci bundle->try_upgrade = false; 8558c2ecf20Sopenharmony_ci if (may_reuse) 8568c2ecf20Sopenharmony_ci rxrpc_activate_channels_locked(bundle); 8578c2ecf20Sopenharmony_ci } 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci } 8608c2ecf20Sopenharmony_ci 8618c2ecf20Sopenharmony_ci /* See if we can pass the channel directly to another call. */ 8628c2ecf20Sopenharmony_ci if (may_reuse && !list_empty(&bundle->waiting_calls)) { 8638c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_chan_pass); 8648c2ecf20Sopenharmony_ci rxrpc_activate_one_channel(conn, channel); 8658c2ecf20Sopenharmony_ci goto out; 8668c2ecf20Sopenharmony_ci } 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci /* Schedule the final ACK to be transmitted in a short while so that it 8698c2ecf20Sopenharmony_ci * can be skipped if we find a follow-on call. The first DATA packet 8708c2ecf20Sopenharmony_ci * of the follow on call will implicitly ACK this call. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci if (call->completion == RXRPC_CALL_SUCCEEDED && 8738c2ecf20Sopenharmony_ci test_bit(RXRPC_CALL_EXPOSED, &call->flags)) { 8748c2ecf20Sopenharmony_ci unsigned long final_ack_at = jiffies + 2; 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_ci WRITE_ONCE(chan->final_ack_at, final_ack_at); 8778c2ecf20Sopenharmony_ci smp_wmb(); /* vs rxrpc_process_delayed_final_acks() */ 8788c2ecf20Sopenharmony_ci set_bit(RXRPC_CONN_FINAL_ACK_0 + channel, &conn->flags); 8798c2ecf20Sopenharmony_ci rxrpc_reduce_conn_timer(conn, final_ack_at); 8808c2ecf20Sopenharmony_ci } 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci /* Deactivate the channel. */ 8838c2ecf20Sopenharmony_ci rcu_assign_pointer(chan->call, NULL); 8848c2ecf20Sopenharmony_ci set_bit(conn->bundle_shift + channel, &conn->bundle->avail_chans); 8858c2ecf20Sopenharmony_ci conn->act_chans &= ~(1 << channel); 8868c2ecf20Sopenharmony_ci 8878c2ecf20Sopenharmony_ci /* If no channels remain active, then put the connection on the idle 8888c2ecf20Sopenharmony_ci * list for a short while. Give it a ref to stop it going away if it 8898c2ecf20Sopenharmony_ci * becomes unbundled. 8908c2ecf20Sopenharmony_ci */ 8918c2ecf20Sopenharmony_ci if (!conn->act_chans) { 8928c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, channel, rxrpc_client_to_idle); 8938c2ecf20Sopenharmony_ci conn->idle_timestamp = jiffies; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci rxrpc_get_connection(conn); 8968c2ecf20Sopenharmony_ci spin_lock(&rxnet->client_conn_cache_lock); 8978c2ecf20Sopenharmony_ci list_move_tail(&conn->cache_link, &rxnet->idle_client_conns); 8988c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci rxrpc_set_client_reap_timer(rxnet); 9018c2ecf20Sopenharmony_ci } 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ciout: 9048c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 9058c2ecf20Sopenharmony_ci _leave(""); 9068c2ecf20Sopenharmony_ci return; 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci/* 9108c2ecf20Sopenharmony_ci * Remove a connection from a bundle. 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_cistatic void rxrpc_unbundle_conn(struct rxrpc_connection *conn) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct rxrpc_bundle *bundle = conn->bundle; 9158c2ecf20Sopenharmony_ci unsigned int bindex; 9168c2ecf20Sopenharmony_ci bool need_drop = false; 9178c2ecf20Sopenharmony_ci int i; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci _enter("C=%x", conn->debug_id); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci if (conn->flags & RXRPC_CONN_FINAL_ACK_MASK) 9228c2ecf20Sopenharmony_ci rxrpc_process_delayed_final_acks(conn, true); 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci spin_lock(&bundle->channel_lock); 9258c2ecf20Sopenharmony_ci bindex = conn->bundle_shift / RXRPC_MAXCALLS; 9268c2ecf20Sopenharmony_ci if (bundle->conns[bindex] == conn) { 9278c2ecf20Sopenharmony_ci _debug("clear slot %u", bindex); 9288c2ecf20Sopenharmony_ci bundle->conns[bindex] = NULL; 9298c2ecf20Sopenharmony_ci for (i = 0; i < RXRPC_MAXCALLS; i++) 9308c2ecf20Sopenharmony_ci clear_bit(conn->bundle_shift + i, &bundle->avail_chans); 9318c2ecf20Sopenharmony_ci need_drop = true; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci spin_unlock(&bundle->channel_lock); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci if (need_drop) { 9368c2ecf20Sopenharmony_ci rxrpc_deactivate_bundle(bundle); 9378c2ecf20Sopenharmony_ci rxrpc_put_connection(conn); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci} 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci/* 9428c2ecf20Sopenharmony_ci * Drop the active count on a bundle. 9438c2ecf20Sopenharmony_ci */ 9448c2ecf20Sopenharmony_cistatic void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle) 9458c2ecf20Sopenharmony_ci{ 9468c2ecf20Sopenharmony_ci struct rxrpc_local *local = bundle->params.local; 9478c2ecf20Sopenharmony_ci bool need_put = false; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (atomic_dec_and_lock(&bundle->active, &local->client_bundles_lock)) { 9508c2ecf20Sopenharmony_ci if (!bundle->params.exclusive) { 9518c2ecf20Sopenharmony_ci _debug("erase bundle"); 9528c2ecf20Sopenharmony_ci rb_erase(&bundle->local_node, &local->client_bundles); 9538c2ecf20Sopenharmony_ci need_put = true; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci spin_unlock(&local->client_bundles_lock); 9578c2ecf20Sopenharmony_ci if (need_put) 9588c2ecf20Sopenharmony_ci rxrpc_put_bundle(bundle); 9598c2ecf20Sopenharmony_ci } 9608c2ecf20Sopenharmony_ci} 9618c2ecf20Sopenharmony_ci 9628c2ecf20Sopenharmony_ci/* 9638c2ecf20Sopenharmony_ci * Clean up a dead client connection. 9648c2ecf20Sopenharmony_ci */ 9658c2ecf20Sopenharmony_cistatic void rxrpc_kill_client_conn(struct rxrpc_connection *conn) 9668c2ecf20Sopenharmony_ci{ 9678c2ecf20Sopenharmony_ci struct rxrpc_local *local = conn->params.local; 9688c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci _enter("C=%x", conn->debug_id); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, -1, rxrpc_client_cleanup); 9738c2ecf20Sopenharmony_ci atomic_dec(&rxnet->nr_client_conns); 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci rxrpc_put_client_connection_id(conn); 9768c2ecf20Sopenharmony_ci rxrpc_kill_connection(conn); 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci/* 9808c2ecf20Sopenharmony_ci * Clean up a dead client connections. 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_civoid rxrpc_put_client_conn(struct rxrpc_connection *conn) 9838c2ecf20Sopenharmony_ci{ 9848c2ecf20Sopenharmony_ci const void *here = __builtin_return_address(0); 9858c2ecf20Sopenharmony_ci unsigned int debug_id = conn->debug_id; 9868c2ecf20Sopenharmony_ci bool dead; 9878c2ecf20Sopenharmony_ci int r; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci dead = __refcount_dec_and_test(&conn->ref, &r); 9908c2ecf20Sopenharmony_ci trace_rxrpc_conn(debug_id, rxrpc_conn_put_client, r - 1, here); 9918c2ecf20Sopenharmony_ci if (dead) 9928c2ecf20Sopenharmony_ci rxrpc_kill_client_conn(conn); 9938c2ecf20Sopenharmony_ci} 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci/* 9968c2ecf20Sopenharmony_ci * Discard expired client connections from the idle list. Each conn in the 9978c2ecf20Sopenharmony_ci * idle list has been exposed and holds an extra ref because of that. 9988c2ecf20Sopenharmony_ci * 9998c2ecf20Sopenharmony_ci * This may be called from conn setup or from a work item so cannot be 10008c2ecf20Sopenharmony_ci * considered non-reentrant. 10018c2ecf20Sopenharmony_ci */ 10028c2ecf20Sopenharmony_civoid rxrpc_discard_expired_client_conns(struct work_struct *work) 10038c2ecf20Sopenharmony_ci{ 10048c2ecf20Sopenharmony_ci struct rxrpc_connection *conn; 10058c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = 10068c2ecf20Sopenharmony_ci container_of(work, struct rxrpc_net, client_conn_reaper); 10078c2ecf20Sopenharmony_ci unsigned long expiry, conn_expires_at, now; 10088c2ecf20Sopenharmony_ci unsigned int nr_conns; 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci _enter(""); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (list_empty(&rxnet->idle_client_conns)) { 10138c2ecf20Sopenharmony_ci _leave(" [empty]"); 10148c2ecf20Sopenharmony_ci return; 10158c2ecf20Sopenharmony_ci } 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* Don't double up on the discarding */ 10188c2ecf20Sopenharmony_ci if (!spin_trylock(&rxnet->client_conn_discard_lock)) { 10198c2ecf20Sopenharmony_ci _leave(" [already]"); 10208c2ecf20Sopenharmony_ci return; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci 10238c2ecf20Sopenharmony_ci /* We keep an estimate of what the number of conns ought to be after 10248c2ecf20Sopenharmony_ci * we've discarded some so that we don't overdo the discarding. 10258c2ecf20Sopenharmony_ci */ 10268c2ecf20Sopenharmony_ci nr_conns = atomic_read(&rxnet->nr_client_conns); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_cinext: 10298c2ecf20Sopenharmony_ci spin_lock(&rxnet->client_conn_cache_lock); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci if (list_empty(&rxnet->idle_client_conns)) 10328c2ecf20Sopenharmony_ci goto out; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci conn = list_entry(rxnet->idle_client_conns.next, 10358c2ecf20Sopenharmony_ci struct rxrpc_connection, cache_link); 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ci if (!rxnet->kill_all_client_conns) { 10388c2ecf20Sopenharmony_ci /* If the number of connections is over the reap limit, we 10398c2ecf20Sopenharmony_ci * expedite discard by reducing the expiry timeout. We must, 10408c2ecf20Sopenharmony_ci * however, have at least a short grace period to be able to do 10418c2ecf20Sopenharmony_ci * final-ACK or ABORT retransmission. 10428c2ecf20Sopenharmony_ci */ 10438c2ecf20Sopenharmony_ci expiry = rxrpc_conn_idle_client_expiry; 10448c2ecf20Sopenharmony_ci if (nr_conns > rxrpc_reap_client_connections) 10458c2ecf20Sopenharmony_ci expiry = rxrpc_conn_idle_client_fast_expiry; 10468c2ecf20Sopenharmony_ci if (conn->params.local->service_closed) 10478c2ecf20Sopenharmony_ci expiry = rxrpc_closed_conn_expiry * HZ; 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci conn_expires_at = conn->idle_timestamp + expiry; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci now = READ_ONCE(jiffies); 10528c2ecf20Sopenharmony_ci if (time_after(conn_expires_at, now)) 10538c2ecf20Sopenharmony_ci goto not_yet_expired; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, -1, rxrpc_client_discard); 10578c2ecf20Sopenharmony_ci list_del_init(&conn->cache_link); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci rxrpc_unbundle_conn(conn); 10628c2ecf20Sopenharmony_ci rxrpc_put_connection(conn); /* Drop the ->cache_link ref */ 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci nr_conns--; 10658c2ecf20Sopenharmony_ci goto next; 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_cinot_yet_expired: 10688c2ecf20Sopenharmony_ci /* The connection at the front of the queue hasn't yet expired, so 10698c2ecf20Sopenharmony_ci * schedule the work item for that point if we discarded something. 10708c2ecf20Sopenharmony_ci * 10718c2ecf20Sopenharmony_ci * We don't worry if the work item is already scheduled - it can look 10728c2ecf20Sopenharmony_ci * after rescheduling itself at a later time. We could cancel it, but 10738c2ecf20Sopenharmony_ci * then things get messier. 10748c2ecf20Sopenharmony_ci */ 10758c2ecf20Sopenharmony_ci _debug("not yet"); 10768c2ecf20Sopenharmony_ci if (!rxnet->kill_all_client_conns) 10778c2ecf20Sopenharmony_ci timer_reduce(&rxnet->client_conn_reap_timer, conn_expires_at); 10788c2ecf20Sopenharmony_ci 10798c2ecf20Sopenharmony_ciout: 10808c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 10818c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_discard_lock); 10828c2ecf20Sopenharmony_ci _leave(""); 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci/* 10868c2ecf20Sopenharmony_ci * Preemptively destroy all the client connection records rather than waiting 10878c2ecf20Sopenharmony_ci * for them to time out 10888c2ecf20Sopenharmony_ci */ 10898c2ecf20Sopenharmony_civoid rxrpc_destroy_all_client_connections(struct rxrpc_net *rxnet) 10908c2ecf20Sopenharmony_ci{ 10918c2ecf20Sopenharmony_ci _enter(""); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci spin_lock(&rxnet->client_conn_cache_lock); 10948c2ecf20Sopenharmony_ci rxnet->kill_all_client_conns = true; 10958c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci del_timer_sync(&rxnet->client_conn_reap_timer); 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci if (!rxrpc_queue_work(&rxnet->client_conn_reaper)) 11008c2ecf20Sopenharmony_ci _debug("destroy: queue failed"); 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci _leave(""); 11038c2ecf20Sopenharmony_ci} 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci/* 11068c2ecf20Sopenharmony_ci * Clean up the client connections on a local endpoint. 11078c2ecf20Sopenharmony_ci */ 11088c2ecf20Sopenharmony_civoid rxrpc_clean_up_local_conns(struct rxrpc_local *local) 11098c2ecf20Sopenharmony_ci{ 11108c2ecf20Sopenharmony_ci struct rxrpc_connection *conn, *tmp; 11118c2ecf20Sopenharmony_ci struct rxrpc_net *rxnet = local->rxnet; 11128c2ecf20Sopenharmony_ci LIST_HEAD(graveyard); 11138c2ecf20Sopenharmony_ci 11148c2ecf20Sopenharmony_ci _enter(""); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci spin_lock(&rxnet->client_conn_cache_lock); 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci list_for_each_entry_safe(conn, tmp, &rxnet->idle_client_conns, 11198c2ecf20Sopenharmony_ci cache_link) { 11208c2ecf20Sopenharmony_ci if (conn->params.local == local) { 11218c2ecf20Sopenharmony_ci trace_rxrpc_client(conn, -1, rxrpc_client_discard); 11228c2ecf20Sopenharmony_ci list_move(&conn->cache_link, &graveyard); 11238c2ecf20Sopenharmony_ci } 11248c2ecf20Sopenharmony_ci } 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci spin_unlock(&rxnet->client_conn_cache_lock); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci while (!list_empty(&graveyard)) { 11298c2ecf20Sopenharmony_ci conn = list_entry(graveyard.next, 11308c2ecf20Sopenharmony_ci struct rxrpc_connection, cache_link); 11318c2ecf20Sopenharmony_ci list_del_init(&conn->cache_link); 11328c2ecf20Sopenharmony_ci rxrpc_unbundle_conn(conn); 11338c2ecf20Sopenharmony_ci rxrpc_put_connection(conn); 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci _leave(" [culled]"); 11378c2ecf20Sopenharmony_ci} 1138