xref: /openbmc/linux/net/rxrpc/conn_object.c (revision 360823a09426347ea8f232b0b0b5156d0aed0302)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
245025bceSDavid Howells /* RxRPC virtual connection handler, common bits.
38c3e34a4SDavid Howells  *
445025bceSDavid Howells  * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved.
58c3e34a4SDavid Howells  * Written by David Howells (dhowells@redhat.com)
68c3e34a4SDavid Howells  */
78c3e34a4SDavid Howells 
88c3e34a4SDavid Howells #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c3e34a4SDavid Howells 
108c3e34a4SDavid Howells #include <linux/module.h>
118c3e34a4SDavid Howells #include <linux/slab.h>
128c3e34a4SDavid Howells #include <linux/net.h>
138c3e34a4SDavid Howells #include <linux/skbuff.h>
148c3e34a4SDavid Howells #include "ar-internal.h"
158c3e34a4SDavid Howells 
168c3e34a4SDavid Howells /*
178c3e34a4SDavid Howells  * Time till a connection expires after last use (in seconds).
188c3e34a4SDavid Howells  */
19f859ab61SDavid Howells unsigned int __read_mostly rxrpc_connection_expiry = 10 * 60;
20f859ab61SDavid Howells unsigned int __read_mostly rxrpc_closed_conn_expiry = 10;
218c3e34a4SDavid Howells 
223cec055cSDavid Howells static void rxrpc_clean_up_connection(struct work_struct *work);
233cec055cSDavid Howells static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,
243cec055cSDavid Howells 					 unsigned long reap_at);
2545025bceSDavid Howells 
rxrpc_poke_conn(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)26f2cce89aSDavid Howells void rxrpc_poke_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
27f2cce89aSDavid Howells {
28f2cce89aSDavid Howells 	struct rxrpc_local *local = conn->local;
29f2cce89aSDavid Howells 	bool busy;
30f2cce89aSDavid Howells 
31f2cce89aSDavid Howells 	if (WARN_ON_ONCE(!local))
32f2cce89aSDavid Howells 		return;
33f2cce89aSDavid Howells 
34f2cce89aSDavid Howells 	spin_lock_bh(&local->lock);
35f2cce89aSDavid Howells 	busy = !list_empty(&conn->attend_link);
36f2cce89aSDavid Howells 	if (!busy) {
37f2cce89aSDavid Howells 		rxrpc_get_connection(conn, why);
38f2cce89aSDavid Howells 		list_add_tail(&conn->attend_link, &local->conn_attend_q);
39f2cce89aSDavid Howells 	}
40f2cce89aSDavid Howells 	spin_unlock_bh(&local->lock);
41f2cce89aSDavid Howells 	rxrpc_wake_up_io_thread(local);
42f2cce89aSDavid Howells }
43f2cce89aSDavid Howells 
rxrpc_connection_timer(struct timer_list * timer)443136ef49SDavid Howells static void rxrpc_connection_timer(struct timer_list *timer)
453136ef49SDavid Howells {
463136ef49SDavid Howells 	struct rxrpc_connection *conn =
473136ef49SDavid Howells 		container_of(timer, struct rxrpc_connection, timer);
483136ef49SDavid Howells 
49f2cce89aSDavid Howells 	rxrpc_poke_conn(conn, rxrpc_conn_get_poke_timer);
503136ef49SDavid Howells }
513136ef49SDavid Howells 
528c3e34a4SDavid Howells /*
538c3e34a4SDavid Howells  * allocate a new connection
548c3e34a4SDavid Howells  */
rxrpc_alloc_connection(struct rxrpc_net * rxnet,gfp_t gfp)553cec055cSDavid Howells struct rxrpc_connection *rxrpc_alloc_connection(struct rxrpc_net *rxnet,
563cec055cSDavid Howells 						gfp_t gfp)
578c3e34a4SDavid Howells {
588c3e34a4SDavid Howells 	struct rxrpc_connection *conn;
598c3e34a4SDavid Howells 
608c3e34a4SDavid Howells 	_enter("");
618c3e34a4SDavid Howells 
628c3e34a4SDavid Howells 	conn = kzalloc(sizeof(struct rxrpc_connection), gfp);
638c3e34a4SDavid Howells 	if (conn) {
6445025bceSDavid Howells 		INIT_LIST_HEAD(&conn->cache_link);
653136ef49SDavid Howells 		timer_setup(&conn->timer, &rxrpc_connection_timer, 0);
663cec055cSDavid Howells 		INIT_WORK(&conn->processor, rxrpc_process_connection);
673cec055cSDavid Howells 		INIT_WORK(&conn->destructor, rxrpc_clean_up_connection);
684d028b2cSDavid Howells 		INIT_LIST_HEAD(&conn->proc_link);
69999b69f8SDavid Howells 		INIT_LIST_HEAD(&conn->link);
70*f7627c81SDavid Howells 		INIT_LIST_HEAD(&conn->attend_link);
719d35d880SDavid Howells 		mutex_init(&conn->security_lock);
728c3e34a4SDavid Howells 		skb_queue_head_init(&conn->rx_queue);
733cec055cSDavid Howells 		conn->rxnet = rxnet;
748c3e34a4SDavid Howells 		conn->security = &rxrpc_no_security;
758c3e34a4SDavid Howells 		spin_lock_init(&conn->state_lock);
768c3e34a4SDavid Howells 		conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
77f51b4480SDavid Howells 		conn->idle_timestamp = jiffies;
788c3e34a4SDavid Howells 	}
798c3e34a4SDavid Howells 
808c3e34a4SDavid Howells 	_leave(" = %p{%d}", conn, conn ? conn->debug_id : 0);
818c3e34a4SDavid Howells 	return conn;
828c3e34a4SDavid Howells }
838c3e34a4SDavid Howells 
848c3e34a4SDavid Howells /*
858496af50SDavid Howells  * Look up a connection in the cache by protocol parameters.
868496af50SDavid Howells  *
878496af50SDavid Howells  * If successful, a pointer to the connection is returned, but no ref is taken.
888496af50SDavid Howells  * NULL is returned if there is no match.
898496af50SDavid Howells  *
900099dc58SDavid Howells  * When searching for a service call, if we find a peer but no connection, we
910099dc58SDavid Howells  * return that through *_peer in case we need to create a new service call.
920099dc58SDavid Howells  *
938496af50SDavid Howells  * The caller must be holding the RCU read lock.
948c3e34a4SDavid Howells  */
rxrpc_find_client_connection_rcu(struct rxrpc_local * local,struct sockaddr_rxrpc * srx,struct sk_buff * skb)955e6ef4f1SDavid Howells struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *local,
96393a2a20SDavid Howells 							  struct sockaddr_rxrpc *srx,
975e6ef4f1SDavid Howells 							  struct sk_buff *skb)
988c3e34a4SDavid Howells {
998c3e34a4SDavid Howells 	struct rxrpc_connection *conn;
10042886ffeSDavid Howells 	struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
1011291e9d1SDavid Howells 	struct rxrpc_peer *peer;
1028c3e34a4SDavid Howells 
1038496af50SDavid Howells 	_enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
1048c3e34a4SDavid Howells 
105f06cb291SDavid Howells 	/* Look up client connections by connection ID alone as their
106f06cb291SDavid Howells 	 * IDs are unique for this machine.
1078496af50SDavid Howells 	 */
108f06cb291SDavid Howells 	conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
109a0575429SDavid Howells 	if (!conn || refcount_read(&conn->ref) == 0) {
1108496af50SDavid Howells 		_debug("no conn");
1118496af50SDavid Howells 		goto not_found;
1128496af50SDavid Howells 	}
1138496af50SDavid Howells 
1145e6ef4f1SDavid Howells 	if (conn->proto.epoch != sp->hdr.epoch ||
1152cc80086SDavid Howells 	    conn->local != local)
1161291e9d1SDavid Howells 		goto not_found;
1171291e9d1SDavid Howells 
1182cc80086SDavid Howells 	peer = conn->peer;
119393a2a20SDavid Howells 	switch (srx->transport.family) {
1201291e9d1SDavid Howells 	case AF_INET:
1211291e9d1SDavid Howells 		if (peer->srx.transport.sin.sin_port !=
12273f81e5aSJeffrey Altman 		    srx->transport.sin.sin_port)
1231291e9d1SDavid Howells 			goto not_found;
1241291e9d1SDavid Howells 		break;
125d1912747SDavid Howells #ifdef CONFIG_AF_RXRPC_IPV6
12675b54cb5SDavid Howells 	case AF_INET6:
12775b54cb5SDavid Howells 		if (peer->srx.transport.sin6.sin6_port !=
12873f81e5aSJeffrey Altman 		    srx->transport.sin6.sin6_port)
12975b54cb5SDavid Howells 			goto not_found;
13075b54cb5SDavid Howells 		break;
131d1912747SDavid Howells #endif
1321291e9d1SDavid Howells 	default:
1331291e9d1SDavid Howells 		BUG();
1344a3388c8SDavid Howells 	}
1358c3e34a4SDavid Howells 
1361291e9d1SDavid Howells 	_leave(" = %p", conn);
1371291e9d1SDavid Howells 	return conn;
1381291e9d1SDavid Howells 
1391291e9d1SDavid Howells not_found:
1408c3e34a4SDavid Howells 	_leave(" = NULL");
1418c3e34a4SDavid Howells 	return NULL;
1428c3e34a4SDavid Howells }
1438c3e34a4SDavid Howells 
1448c3e34a4SDavid Howells /*
145999b69f8SDavid Howells  * Disconnect a call and clear any channel it occupies when that call
146a1399f8bSDavid Howells  * terminates.  The caller must hold the channel_lock and must release the
147a1399f8bSDavid Howells  * call's ref on the connection.
148a1399f8bSDavid Howells  */
__rxrpc_disconnect_call(struct rxrpc_connection * conn,struct rxrpc_call * call)14945025bceSDavid Howells void __rxrpc_disconnect_call(struct rxrpc_connection *conn,
15045025bceSDavid Howells 			     struct rxrpc_call *call)
151a1399f8bSDavid Howells {
15201a90a45SDavid Howells 	struct rxrpc_channel *chan =
15301a90a45SDavid Howells 		&conn->channels[call->cid & RXRPC_CHANNELMASK];
154a1399f8bSDavid Howells 
15501a90a45SDavid Howells 	_enter("%d,%x", conn->debug_id, call->cid);
156a1399f8bSDavid Howells 
1579d35d880SDavid Howells 	if (chan->call == call) {
158a1399f8bSDavid Howells 		/* Save the result of the call so that we can repeat it if necessary
159a1399f8bSDavid Howells 		 * through the channel, whilst disposing of the actual call record.
160a1399f8bSDavid Howells 		 */
161b1d9f7fdSDavid Howells 		trace_rxrpc_disconnect_call(call);
16217e9e23bSDavid Howells 		switch (call->completion) {
16317e9e23bSDavid Howells 		case RXRPC_CALL_SUCCEEDED:
1645d7edbc9SDavid Howells 			chan->last_seq = call->rx_highest_seq;
16518bfeba5SDavid Howells 			chan->last_type = RXRPC_PACKET_TYPE_ACK;
16617e9e23bSDavid Howells 			break;
16717e9e23bSDavid Howells 		case RXRPC_CALL_LOCALLY_ABORTED:
16817e9e23bSDavid Howells 			chan->last_abort = call->abort_code;
16917e9e23bSDavid Howells 			chan->last_type = RXRPC_PACKET_TYPE_ABORT;
17017e9e23bSDavid Howells 			break;
17117e9e23bSDavid Howells 		default:
172de696c47SDavid Howells 			chan->last_abort = RX_CALL_DEAD;
17317e9e23bSDavid Howells 			chan->last_type = RXRPC_PACKET_TYPE_ABORT;
17417e9e23bSDavid Howells 			break;
17518bfeba5SDavid Howells 		}
17617e9e23bSDavid Howells 
177a1399f8bSDavid Howells 		chan->last_call = chan->call_id;
178a1399f8bSDavid Howells 		chan->call_id = chan->call_counter;
1799d35d880SDavid Howells 		chan->call = NULL;
180a1399f8bSDavid Howells 	}
181a1399f8bSDavid Howells 
182a1399f8bSDavid Howells 	_leave("");
183a1399f8bSDavid Howells }
184a1399f8bSDavid Howells 
185a1399f8bSDavid Howells /*
186a1399f8bSDavid Howells  * Disconnect a call and clear any channel it occupies when that call
187999b69f8SDavid Howells  * terminates.
188999b69f8SDavid Howells  */
rxrpc_disconnect_call(struct rxrpc_call * call)189999b69f8SDavid Howells void rxrpc_disconnect_call(struct rxrpc_call *call)
190999b69f8SDavid Howells {
191999b69f8SDavid Howells 	struct rxrpc_connection *conn = call->conn;
192999b69f8SDavid Howells 
1935040011dSDavid Howells 	set_bit(RXRPC_CALL_DISCONNECTED, &call->flags);
1945040011dSDavid Howells 	rxrpc_see_call(call, rxrpc_call_see_disconnected);
1955040011dSDavid Howells 
1961fc4fa2aSDavid Howells 	call->peer->cong_ssthresh = call->cong_ssthresh;
197f7aec129SDavid Howells 
19865550098SDavid Howells 	if (!hlist_unhashed(&call->error_link)) {
19929fb4ec3SDavid Howells 		spin_lock(&call->peer->lock);
20029fb4ec3SDavid Howells 		hlist_del_init(&call->error_link);
20129fb4ec3SDavid Howells 		spin_unlock(&call->peer->lock);
20265550098SDavid Howells 	}
203248f219cSDavid Howells 
2045040011dSDavid Howells 	if (rxrpc_is_client_call(call)) {
2051bab27afSDavid Howells 		rxrpc_disconnect_client_call(call->bundle, call);
2065040011dSDavid Howells 	} else {
20745025bceSDavid Howells 		__rxrpc_disconnect_call(conn, call);
208f51b4480SDavid Howells 		conn->idle_timestamp = jiffies;
2093cec055cSDavid Howells 		if (atomic_dec_and_test(&conn->active))
2103cec055cSDavid Howells 			rxrpc_set_service_reap_timer(conn->rxnet,
211b8a4f0a2SDavid Howells 						     jiffies + rxrpc_connection_expiry * HZ);
21245025bceSDavid Howells 	}
21345025bceSDavid Howells 
2145040011dSDavid Howells 	rxrpc_put_call(call, rxrpc_call_put_io_thread);
2155040011dSDavid Howells }
2165040011dSDavid Howells 
21745025bceSDavid Howells /*
218363deeabSDavid Howells  * Queue a connection's work processor, getting a ref to pass to the work
219363deeabSDavid Howells  * queue.
2208c3e34a4SDavid Howells  */
rxrpc_queue_conn(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)2213cec055cSDavid Howells void rxrpc_queue_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
2228c3e34a4SDavid Howells {
2233cec055cSDavid Howells 	if (atomic_read(&conn->active) >= 0 &&
2243cec055cSDavid Howells 	    rxrpc_queue_work(&conn->processor))
2253cec055cSDavid Howells 		rxrpc_see_connection(conn, why);
226363deeabSDavid Howells }
227363deeabSDavid Howells 
228363deeabSDavid Howells /*
229363deeabSDavid Howells  * Note the re-emergence of a connection.
230363deeabSDavid Howells  */
rxrpc_see_connection(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)2317fa25105SDavid Howells void rxrpc_see_connection(struct rxrpc_connection *conn,
2327fa25105SDavid Howells 			  enum rxrpc_conn_trace why)
233363deeabSDavid Howells {
234363deeabSDavid Howells 	if (conn) {
2357fa25105SDavid Howells 		int r = refcount_read(&conn->ref);
236363deeabSDavid Howells 
2377fa25105SDavid Howells 		trace_rxrpc_conn(conn->debug_id, r, why);
238363deeabSDavid Howells 	}
239363deeabSDavid Howells }
240363deeabSDavid Howells 
241363deeabSDavid Howells /*
242363deeabSDavid Howells  * Get a ref on a connection.
243363deeabSDavid Howells  */
rxrpc_get_connection(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)2447fa25105SDavid Howells struct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *conn,
2457fa25105SDavid Howells 					      enum rxrpc_conn_trace why)
246363deeabSDavid Howells {
247a0575429SDavid Howells 	int r;
248363deeabSDavid Howells 
249a0575429SDavid Howells 	__refcount_inc(&conn->ref, &r);
2507fa25105SDavid Howells 	trace_rxrpc_conn(conn->debug_id, r + 1, why);
251245500d8SDavid Howells 	return conn;
252363deeabSDavid Howells }
253363deeabSDavid Howells 
254363deeabSDavid Howells /*
255363deeabSDavid Howells  * Try to get a ref on a connection.
256363deeabSDavid Howells  */
257363deeabSDavid Howells struct rxrpc_connection *
rxrpc_get_connection_maybe(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)2587fa25105SDavid Howells rxrpc_get_connection_maybe(struct rxrpc_connection *conn,
2597fa25105SDavid Howells 			   enum rxrpc_conn_trace why)
260363deeabSDavid Howells {
261a0575429SDavid Howells 	int r;
262363deeabSDavid Howells 
263363deeabSDavid Howells 	if (conn) {
264a0575429SDavid Howells 		if (__refcount_inc_not_zero(&conn->ref, &r))
2657fa25105SDavid Howells 			trace_rxrpc_conn(conn->debug_id, r + 1, why);
266363deeabSDavid Howells 		else
267363deeabSDavid Howells 			conn = NULL;
268363deeabSDavid Howells 	}
269363deeabSDavid Howells 	return conn;
270363deeabSDavid Howells }
271363deeabSDavid Howells 
272363deeabSDavid Howells /*
2733d18cbb7SDavid Howells  * Set the service connection reap timer.
2743d18cbb7SDavid Howells  */
rxrpc_set_service_reap_timer(struct rxrpc_net * rxnet,unsigned long reap_at)2753d18cbb7SDavid Howells static void rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet,
2763d18cbb7SDavid Howells 					 unsigned long reap_at)
2773d18cbb7SDavid Howells {
2783d18cbb7SDavid Howells 	if (rxnet->live)
2793d18cbb7SDavid Howells 		timer_reduce(&rxnet->service_conn_reap_timer, reap_at);
2803d18cbb7SDavid Howells }
2813d18cbb7SDavid Howells 
2823d18cbb7SDavid Howells /*
2838c3e34a4SDavid Howells  * destroy a virtual connection
2848c3e34a4SDavid Howells  */
rxrpc_rcu_free_connection(struct rcu_head * rcu)2853cec055cSDavid Howells static void rxrpc_rcu_free_connection(struct rcu_head *rcu)
2868c3e34a4SDavid Howells {
287dee46364SDavid Howells 	struct rxrpc_connection *conn =
288dee46364SDavid Howells 		container_of(rcu, struct rxrpc_connection, rcu);
2893cec055cSDavid Howells 	struct rxrpc_net *rxnet = conn->rxnet;
290dee46364SDavid Howells 
291a0575429SDavid Howells 	_enter("{%d,u=%d}", conn->debug_id, refcount_read(&conn->ref));
2928c3e34a4SDavid Howells 
2937fa25105SDavid Howells 	trace_rxrpc_conn(conn->debug_id, refcount_read(&conn->ref),
2947fa25105SDavid Howells 			 rxrpc_conn_free);
2953cec055cSDavid Howells 	kfree(conn);
2967fa25105SDavid Howells 
2973cec055cSDavid Howells 	if (atomic_dec_and_test(&rxnet->nr_conns))
2983cec055cSDavid Howells 		wake_up_var(&rxnet->nr_conns);
2993cec055cSDavid Howells }
3003cec055cSDavid Howells 
3013cec055cSDavid Howells /*
3023cec055cSDavid Howells  * Clean up a dead connection.
3033cec055cSDavid Howells  */
rxrpc_clean_up_connection(struct work_struct * work)3043cec055cSDavid Howells static void rxrpc_clean_up_connection(struct work_struct *work)
3053cec055cSDavid Howells {
3063cec055cSDavid Howells 	struct rxrpc_connection *conn =
3073cec055cSDavid Howells 		container_of(work, struct rxrpc_connection, destructor);
3083cec055cSDavid Howells 	struct rxrpc_net *rxnet = conn->rxnet;
3093cec055cSDavid Howells 
3109d35d880SDavid Howells 	ASSERT(!conn->channels[0].call &&
3119d35d880SDavid Howells 	       !conn->channels[1].call &&
3129d35d880SDavid Howells 	       !conn->channels[2].call &&
3139d35d880SDavid Howells 	       !conn->channels[3].call);
3143cec055cSDavid Howells 	ASSERT(list_empty(&conn->cache_link));
3158c3e34a4SDavid Howells 
3163136ef49SDavid Howells 	del_timer_sync(&conn->timer);
3173cec055cSDavid Howells 	cancel_work_sync(&conn->processor); /* Processing may restart the timer */
3183cec055cSDavid Howells 	del_timer_sync(&conn->timer);
3193cec055cSDavid Howells 
3203cec055cSDavid Howells 	write_lock(&rxnet->conn_lock);
3213cec055cSDavid Howells 	list_del_init(&conn->proc_link);
3223cec055cSDavid Howells 	write_unlock(&rxnet->conn_lock);
3233cec055cSDavid Howells 
3248c3e34a4SDavid Howells 	rxrpc_purge_queue(&conn->rx_queue);
3258c3e34a4SDavid Howells 
3263cec055cSDavid Howells 	rxrpc_kill_client_conn(conn);
3273cec055cSDavid Howells 
3288c3e34a4SDavid Howells 	conn->security->clear(conn);
3292cc80086SDavid Howells 	key_put(conn->key);
330fa3492abSDavid Howells 	rxrpc_put_bundle(conn->bundle, rxrpc_bundle_put_conn);
33147c810a7SDavid Howells 	rxrpc_put_peer(conn->peer, rxrpc_peer_put_conn);
3320fde882fSDavid Howells 	rxrpc_put_local(conn->local, rxrpc_local_put_kill_conn);
3338c3e34a4SDavid Howells 
3343cec055cSDavid Howells 	/* Drain the Rx queue.  Note that even though we've unpublished, an
3353cec055cSDavid Howells 	 * incoming packet could still be being added to our Rx queue, so we
3363cec055cSDavid Howells 	 * will need to drain it again in the RCU cleanup handler.
3373cec055cSDavid Howells 	 */
3383cec055cSDavid Howells 	rxrpc_purge_queue(&conn->rx_queue);
3393cec055cSDavid Howells 
3403cec055cSDavid Howells 	call_rcu(&conn->rcu, rxrpc_rcu_free_connection);
3413cec055cSDavid Howells }
3423cec055cSDavid Howells 
3433cec055cSDavid Howells /*
3443cec055cSDavid Howells  * Drop a ref on a connection.
3453cec055cSDavid Howells  */
rxrpc_put_connection(struct rxrpc_connection * conn,enum rxrpc_conn_trace why)3463cec055cSDavid Howells void rxrpc_put_connection(struct rxrpc_connection *conn,
3473cec055cSDavid Howells 			  enum rxrpc_conn_trace why)
3483cec055cSDavid Howells {
3493cec055cSDavid Howells 	unsigned int debug_id;
3503cec055cSDavid Howells 	bool dead;
3513cec055cSDavid Howells 	int r;
3523cec055cSDavid Howells 
3533cec055cSDavid Howells 	if (!conn)
3543cec055cSDavid Howells 		return;
3553cec055cSDavid Howells 
3563cec055cSDavid Howells 	debug_id = conn->debug_id;
3573cec055cSDavid Howells 	dead = __refcount_dec_and_test(&conn->ref, &r);
3583cec055cSDavid Howells 	trace_rxrpc_conn(debug_id, r - 1, why);
3593cec055cSDavid Howells 	if (dead) {
3603cec055cSDavid Howells 		del_timer(&conn->timer);
3613cec055cSDavid Howells 		cancel_work(&conn->processor);
3623cec055cSDavid Howells 
3633cec055cSDavid Howells 		if (in_softirq() || work_busy(&conn->processor) ||
3643cec055cSDavid Howells 		    timer_pending(&conn->timer))
3653cec055cSDavid Howells 			/* Can't use the rxrpc workqueue as we need to cancel/flush
3663cec055cSDavid Howells 			 * something that may be running/waiting there.
3673cec055cSDavid Howells 			 */
3683cec055cSDavid Howells 			schedule_work(&conn->destructor);
3693cec055cSDavid Howells 		else
3703cec055cSDavid Howells 			rxrpc_clean_up_connection(&conn->destructor);
3713cec055cSDavid Howells 	}
3728c3e34a4SDavid Howells }
3738c3e34a4SDavid Howells 
3748c3e34a4SDavid Howells /*
37545025bceSDavid Howells  * reap dead service connections
3768c3e34a4SDavid Howells  */
rxrpc_service_connection_reaper(struct work_struct * work)3772baec2c3SDavid Howells void rxrpc_service_connection_reaper(struct work_struct *work)
3788c3e34a4SDavid Howells {
3798c3e34a4SDavid Howells 	struct rxrpc_connection *conn, *_p;
3802baec2c3SDavid Howells 	struct rxrpc_net *rxnet =
3813d18cbb7SDavid Howells 		container_of(work, struct rxrpc_net, service_conn_reaper);
382f859ab61SDavid Howells 	unsigned long expire_at, earliest, idle_timestamp, now;
3833cec055cSDavid Howells 	int active;
3848c3e34a4SDavid Howells 
3858c3e34a4SDavid Howells 	LIST_HEAD(graveyard);
3868c3e34a4SDavid Howells 
3878c3e34a4SDavid Howells 	_enter("");
3888c3e34a4SDavid Howells 
389f51b4480SDavid Howells 	now = jiffies;
390f859ab61SDavid Howells 	earliest = now + MAX_JIFFY_OFFSET;
3918c3e34a4SDavid Howells 
3922baec2c3SDavid Howells 	write_lock(&rxnet->conn_lock);
3932baec2c3SDavid Howells 	list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) {
3943cec055cSDavid Howells 		ASSERTCMP(atomic_read(&conn->active), >=, 0);
3953cec055cSDavid Howells 		if (likely(atomic_read(&conn->active) > 0))
3968c3e34a4SDavid Howells 			continue;
39700e90712SDavid Howells 		if (conn->state == RXRPC_CONN_SERVICE_PREALLOC)
39800e90712SDavid Howells 			continue;
3998c3e34a4SDavid Howells 
4002cc80086SDavid Howells 		if (rxnet->live && !conn->local->dead) {
401f51b4480SDavid Howells 			idle_timestamp = READ_ONCE(conn->idle_timestamp);
402f859ab61SDavid Howells 			expire_at = idle_timestamp + rxrpc_connection_expiry * HZ;
4032cc80086SDavid Howells 			if (conn->local->service_closed)
404f859ab61SDavid Howells 				expire_at = idle_timestamp + rxrpc_closed_conn_expiry * HZ;
405f859ab61SDavid Howells 
4063cec055cSDavid Howells 			_debug("reap CONN %d { a=%d,t=%ld }",
4073cec055cSDavid Howells 			       conn->debug_id, atomic_read(&conn->active),
408f859ab61SDavid Howells 			       (long)expire_at - (long)now);
409f51b4480SDavid Howells 
410f859ab61SDavid Howells 			if (time_before(now, expire_at)) {
411f859ab61SDavid Howells 				if (time_before(expire_at, earliest))
412f859ab61SDavid Howells 					earliest = expire_at;
413001c1122SDavid Howells 				continue;
414001c1122SDavid Howells 			}
415f859ab61SDavid Howells 		}
416999b69f8SDavid Howells 
4173cec055cSDavid Howells 		/* The activity count sits at 0 whilst the conn is unused on
4183cec055cSDavid Howells 		 * the list; we reduce that to -1 to make the conn unavailable.
419001c1122SDavid Howells 		 */
4203cec055cSDavid Howells 		active = 0;
4213cec055cSDavid Howells 		if (!atomic_try_cmpxchg(&conn->active, &active, -1))
422001c1122SDavid Howells 			continue;
4237fa25105SDavid Howells 		rxrpc_see_connection(conn, rxrpc_conn_see_reap_service);
424001c1122SDavid Howells 
425001c1122SDavid Howells 		if (rxrpc_conn_is_client(conn))
42645025bceSDavid Howells 			BUG();
427001c1122SDavid Howells 		else
428001c1122SDavid Howells 			rxrpc_unpublish_service_conn(conn);
429001c1122SDavid Howells 
430999b69f8SDavid Howells 		list_move_tail(&conn->link, &graveyard);
4318c3e34a4SDavid Howells 	}
4322baec2c3SDavid Howells 	write_unlock(&rxnet->conn_lock);
4338c3e34a4SDavid Howells 
434f859ab61SDavid Howells 	if (earliest != now + MAX_JIFFY_OFFSET) {
435f859ab61SDavid Howells 		_debug("reschedule reaper %ld", (long)earliest - (long)now);
436f51b4480SDavid Howells 		ASSERT(time_after(earliest, now));
4373d18cbb7SDavid Howells 		rxrpc_set_service_reap_timer(rxnet, earliest);
4388c3e34a4SDavid Howells 	}
4398c3e34a4SDavid Howells 
4408c3e34a4SDavid Howells 	while (!list_empty(&graveyard)) {
4418c3e34a4SDavid Howells 		conn = list_entry(graveyard.next, struct rxrpc_connection,
4428c3e34a4SDavid Howells 				  link);
4438c3e34a4SDavid Howells 		list_del_init(&conn->link);
4448c3e34a4SDavid Howells 
4453cec055cSDavid Howells 		ASSERTCMP(atomic_read(&conn->active), ==, -1);
4463cec055cSDavid Howells 		rxrpc_put_connection(conn, rxrpc_conn_put_service_reaped);
4478c3e34a4SDavid Howells 	}
4488c3e34a4SDavid Howells 
4498c3e34a4SDavid Howells 	_leave("");
4508c3e34a4SDavid Howells }
4518c3e34a4SDavid Howells 
4528c3e34a4SDavid Howells /*
45345025bceSDavid Howells  * preemptively destroy all the service connection records rather than
45445025bceSDavid Howells  * waiting for them to time out
4558c3e34a4SDavid Howells  */
rxrpc_destroy_all_connections(struct rxrpc_net * rxnet)4562baec2c3SDavid Howells void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
4578c3e34a4SDavid Howells {
458dee46364SDavid Howells 	struct rxrpc_connection *conn, *_p;
459dee46364SDavid Howells 	bool leak = false;
460dee46364SDavid Howells 
4618c3e34a4SDavid Howells 	_enter("");
4628c3e34a4SDavid Howells 
46331f5f9a1SDavid Howells 	atomic_dec(&rxnet->nr_conns);
46445025bceSDavid Howells 
4653d18cbb7SDavid Howells 	del_timer_sync(&rxnet->service_conn_reap_timer);
4663d18cbb7SDavid Howells 	rxrpc_queue_work(&rxnet->service_conn_reaper);
467dee46364SDavid Howells 	flush_workqueue(rxrpc_workqueue);
468dee46364SDavid Howells 
4692baec2c3SDavid Howells 	write_lock(&rxnet->conn_lock);
4702baec2c3SDavid Howells 	list_for_each_entry_safe(conn, _p, &rxnet->service_conns, link) {
471dee46364SDavid Howells 		pr_err("AF_RXRPC: Leaked conn %p {%d}\n",
472a0575429SDavid Howells 		       conn, refcount_read(&conn->ref));
473dee46364SDavid Howells 		leak = true;
474dee46364SDavid Howells 	}
4752baec2c3SDavid Howells 	write_unlock(&rxnet->conn_lock);
476dee46364SDavid Howells 	BUG_ON(leak);
477dee46364SDavid Howells 
4782baec2c3SDavid Howells 	ASSERT(list_empty(&rxnet->conn_proc_list));
4798c3e34a4SDavid Howells 
48031f5f9a1SDavid Howells 	/* We need to wait for the connections to be destroyed by RCU as they
48131f5f9a1SDavid Howells 	 * pin things that we still need to get rid of.
48231f5f9a1SDavid Howells 	 */
4835bb053beSLinus Torvalds 	wait_var_event(&rxnet->nr_conns, !atomic_read(&rxnet->nr_conns));
4848c3e34a4SDavid Howells 	_leave("");
4858c3e34a4SDavid Howells }
486