]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - net/rxrpc/conn_object.c
rxrpc: Split service connection code out into its own file
[mirror_ubuntu-artful-kernel.git] / net / rxrpc / conn_object.c
CommitLineData
17926a79
DH
1/* RxRPC virtual connection handler
2 *
3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
9b6d5398
JP
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
17926a79 14#include <linux/module.h>
5a0e3ad6 15#include <linux/slab.h>
17926a79
DH
16#include <linux/net.h>
17#include <linux/skbuff.h>
18#include <linux/crypto.h>
19#include <net/sock.h>
20#include <net/af_rxrpc.h>
21#include "ar-internal.h"
22
5873c083
DH
23/*
24 * Time till a connection expires after last use (in seconds).
25 */
dad8aff7 26unsigned int rxrpc_connection_expiry = 10 * 60;
5873c083 27
17926a79
DH
28static void rxrpc_connection_reaper(struct work_struct *work);
29
30LIST_HEAD(rxrpc_connections);
31DEFINE_RWLOCK(rxrpc_connection_lock);
17926a79
DH
32static DECLARE_DELAYED_WORK(rxrpc_connection_reap, rxrpc_connection_reaper);
33
17926a79
DH
34/*
35 * allocate a new connection
36 */
c6d2b8d7 37struct rxrpc_connection *rxrpc_alloc_connection(gfp_t gfp)
17926a79
DH
38{
39 struct rxrpc_connection *conn;
40
41 _enter("");
42
43 conn = kzalloc(sizeof(struct rxrpc_connection), gfp);
44 if (conn) {
999b69f8
DH
45 spin_lock_init(&conn->channel_lock);
46 init_waitqueue_head(&conn->channel_wq);
17926a79 47 INIT_WORK(&conn->processor, &rxrpc_process_connection);
999b69f8 48 INIT_LIST_HEAD(&conn->link);
17926a79 49 skb_queue_head_init(&conn->rx_queue);
e0e4d82f 50 conn->security = &rxrpc_no_security;
17926a79
DH
51 spin_lock_init(&conn->state_lock);
52 atomic_set(&conn->usage, 1);
53 conn->debug_id = atomic_inc_return(&rxrpc_debug_id);
999b69f8 54 atomic_set(&conn->avail_chans, RXRPC_MAXCALLS);
17926a79 55 conn->size_align = 4;
0d12f8a4 56 conn->header_size = sizeof(struct rxrpc_wire_header);
17926a79
DH
57 }
58
16c61add 59 _leave(" = %p{%d}", conn, conn ? conn->debug_id : 0);
17926a79
DH
60 return conn;
61}
62
17926a79
DH
63/*
64 * find a connection based on transport and RxRPC connection ID for an incoming
65 * packet
66 */
aa390bbe
DH
67struct rxrpc_connection *rxrpc_find_connection(struct rxrpc_local *local,
68 struct rxrpc_peer *peer,
42886ffe 69 struct sk_buff *skb)
17926a79
DH
70{
71 struct rxrpc_connection *conn;
42886ffe 72 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
17926a79 73 struct rb_node *p;
0d12f8a4 74 u32 epoch, cid;
17926a79 75
42886ffe 76 _enter(",{%x,%x}", sp->hdr.cid, sp->hdr.flags);
17926a79 77
aa390bbe 78 read_lock_bh(&peer->conn_lock);
17926a79 79
42886ffe
DH
80 cid = sp->hdr.cid & RXRPC_CIDMASK;
81 epoch = sp->hdr.epoch;
17926a79 82
4a3388c8 83 if (sp->hdr.flags & RXRPC_CLIENT_INITIATED) {
aa390bbe 84 p = peer->service_conns.rb_node;
4a3388c8 85 while (p) {
999b69f8 86 conn = rb_entry(p, struct rxrpc_connection, service_node);
4a3388c8
DH
87
88 _debug("maybe %x", conn->proto.cid);
89
90 if (epoch < conn->proto.epoch)
91 p = p->rb_left;
92 else if (epoch > conn->proto.epoch)
93 p = p->rb_right;
94 else if (cid < conn->proto.cid)
95 p = p->rb_left;
96 else if (cid > conn->proto.cid)
97 p = p->rb_right;
98 else
99 goto found;
100 }
101 } else {
102 conn = idr_find(&rxrpc_client_conn_ids, cid >> RXRPC_CIDSHIFT);
689f4c64
DH
103 if (conn &&
104 conn->proto.epoch == epoch &&
105 conn->params.peer == peer)
17926a79
DH
106 goto found;
107 }
108
aa390bbe 109 read_unlock_bh(&peer->conn_lock);
17926a79
DH
110 _leave(" = NULL");
111 return NULL;
112
113found:
5627cc8b 114 rxrpc_get_connection(conn);
aa390bbe 115 read_unlock_bh(&peer->conn_lock);
17926a79
DH
116 _leave(" = %p", conn);
117 return conn;
118}
119
999b69f8
DH
120/*
121 * Disconnect a call and clear any channel it occupies when that call
a1399f8b
DH
122 * terminates. The caller must hold the channel_lock and must release the
123 * call's ref on the connection.
999b69f8 124 */
a1399f8b 125void __rxrpc_disconnect_call(struct rxrpc_call *call)
999b69f8
DH
126{
127 struct rxrpc_connection *conn = call->conn;
a1399f8b 128 struct rxrpc_channel *chan = &conn->channels[call->channel];
999b69f8
DH
129
130 _enter("%d,%d", conn->debug_id, call->channel);
131
a1399f8b
DH
132 if (rcu_access_pointer(chan->call) == call) {
133 /* Save the result of the call so that we can repeat it if necessary
134 * through the channel, whilst disposing of the actual call record.
135 */
136 chan->last_result = call->local_abort;
137 smp_wmb();
138 chan->last_call = chan->call_id;
139 chan->call_id = chan->call_counter;
e653cfe4 140
a1399f8b 141 rcu_assign_pointer(chan->call, NULL);
999b69f8
DH
142 atomic_inc(&conn->avail_chans);
143 wake_up(&conn->channel_wq);
144 }
e653cfe4 145
a1399f8b
DH
146 _leave("");
147}
148
149/*
150 * Disconnect a call and clear any channel it occupies when that call
151 * terminates.
152 */
153void rxrpc_disconnect_call(struct rxrpc_call *call)
154{
155 struct rxrpc_connection *conn = call->conn;
156
157 spin_lock(&conn->channel_lock);
158 __rxrpc_disconnect_call(call);
e653cfe4
DH
159 spin_unlock(&conn->channel_lock);
160
161 call->conn = NULL;
162 rxrpc_put_connection(conn);
999b69f8
DH
163}
164
17926a79
DH
165/*
166 * release a virtual connection
167 */
168void rxrpc_put_connection(struct rxrpc_connection *conn)
169{
999b69f8
DH
170 if (!conn)
171 return;
172
17926a79
DH
173 _enter("%p{u=%d,d=%d}",
174 conn, atomic_read(&conn->usage), conn->debug_id);
175
176 ASSERTCMP(atomic_read(&conn->usage), >, 0);
177
22a3f9a2 178 conn->put_time = ktime_get_seconds();
17926a79
DH
179 if (atomic_dec_and_test(&conn->usage)) {
180 _debug("zombie");
651350d1 181 rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
17926a79
DH
182 }
183
184 _leave("");
185}
186
187/*
188 * destroy a virtual connection
189 */
dee46364 190static void rxrpc_destroy_connection(struct rcu_head *rcu)
17926a79 191{
dee46364
DH
192 struct rxrpc_connection *conn =
193 container_of(rcu, struct rxrpc_connection, rcu);
194
195 _enter("{%d,u=%d}", conn->debug_id, atomic_read(&conn->usage));
17926a79
DH
196
197 ASSERTCMP(atomic_read(&conn->usage), ==, 0);
198
199 _net("DESTROY CONN %d", conn->debug_id);
200
17926a79
DH
201 rxrpc_purge_queue(&conn->rx_queue);
202
e0e4d82f 203 conn->security->clear(conn);
19ffa01c 204 key_put(conn->params.key);
e0e4d82f 205 key_put(conn->server_key);
aa390bbe
DH
206 rxrpc_put_peer(conn->params.peer);
207 rxrpc_put_local(conn->params.local);
e0e4d82f 208
17926a79
DH
209 kfree(conn);
210 _leave("");
211}
212
213/*
214 * reap dead connections
215 */
5eaa65b2 216static void rxrpc_connection_reaper(struct work_struct *work)
17926a79
DH
217{
218 struct rxrpc_connection *conn, *_p;
aa390bbe 219 struct rxrpc_peer *peer;
17926a79
DH
220 unsigned long now, earliest, reap_time;
221
222 LIST_HEAD(graveyard);
223
224 _enter("");
225
22a3f9a2 226 now = ktime_get_seconds();
17926a79
DH
227 earliest = ULONG_MAX;
228
b3f57504 229 write_lock(&rxrpc_connection_lock);
17926a79
DH
230 list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) {
231 _debug("reap CONN %d { u=%d,t=%ld }",
232 conn->debug_id, atomic_read(&conn->usage),
233 (long) now - (long) conn->put_time);
234
235 if (likely(atomic_read(&conn->usage) > 0))
236 continue;
237
999b69f8
DH
238 if (rxrpc_conn_is_client(conn)) {
239 struct rxrpc_local *local = conn->params.local;
240 spin_lock(&local->client_conns_lock);
241 reap_time = conn->put_time + rxrpc_connection_expiry;
17926a79 242
999b69f8
DH
243 if (atomic_read(&conn->usage) > 0) {
244 ;
245 } else if (reap_time <= now) {
246 list_move_tail(&conn->link, &graveyard);
4a3388c8 247 rxrpc_put_client_connection_id(conn);
999b69f8
DH
248 rb_erase(&conn->client_node,
249 &local->client_conns);
250 } else if (reap_time < earliest) {
251 earliest = reap_time;
252 }
253
254 spin_unlock(&local->client_conns_lock);
255 } else {
aa390bbe
DH
256 peer = conn->params.peer;
257 write_lock_bh(&peer->conn_lock);
999b69f8
DH
258 reap_time = conn->put_time + rxrpc_connection_expiry;
259
260 if (atomic_read(&conn->usage) > 0) {
261 ;
262 } else if (reap_time <= now) {
263 list_move_tail(&conn->link, &graveyard);
264 rb_erase(&conn->service_node,
aa390bbe 265 &peer->service_conns);
999b69f8
DH
266 } else if (reap_time < earliest) {
267 earliest = reap_time;
17926a79
DH
268 }
269
aa390bbe 270 write_unlock_bh(&peer->conn_lock);
17926a79 271 }
17926a79 272 }
b3f57504 273 write_unlock(&rxrpc_connection_lock);
17926a79
DH
274
275 if (earliest != ULONG_MAX) {
276 _debug("reschedule reaper %ld", (long) earliest - now);
277 ASSERTCMP(earliest, >, now);
651350d1
DH
278 rxrpc_queue_delayed_work(&rxrpc_connection_reap,
279 (earliest - now) * HZ);
17926a79
DH
280 }
281
282 /* then destroy all those pulled out */
283 while (!list_empty(&graveyard)) {
284 conn = list_entry(graveyard.next, struct rxrpc_connection,
285 link);
286 list_del_init(&conn->link);
287
288 ASSERTCMP(atomic_read(&conn->usage), ==, 0);
dee46364
DH
289 skb_queue_purge(&conn->rx_queue);
290 call_rcu(&conn->rcu, rxrpc_destroy_connection);
17926a79
DH
291 }
292
293 _leave("");
294}
295
296/*
297 * preemptively destroy all the connection records rather than waiting for them
298 * to time out
299 */
300void __exit rxrpc_destroy_all_connections(void)
301{
dee46364
DH
302 struct rxrpc_connection *conn, *_p;
303 bool leak = false;
304
17926a79
DH
305 _enter("");
306
5873c083 307 rxrpc_connection_expiry = 0;
17926a79 308 cancel_delayed_work(&rxrpc_connection_reap);
651350d1 309 rxrpc_queue_delayed_work(&rxrpc_connection_reap, 0);
dee46364
DH
310 flush_workqueue(rxrpc_workqueue);
311
312 write_lock(&rxrpc_connection_lock);
313 list_for_each_entry_safe(conn, _p, &rxrpc_connections, link) {
314 pr_err("AF_RXRPC: Leaked conn %p {%d}\n",
315 conn, atomic_read(&conn->usage));
316 leak = true;
317 }
318 write_unlock(&rxrpc_connection_lock);
319 BUG_ON(leak);
320
321 /* Make sure the local and peer records pinned by any dying connections
322 * are released.
323 */
324 rcu_barrier();
325 rxrpc_destroy_client_conn_ids();
17926a79
DH
326
327 _leave("");
328}