Blame view
net/rxrpc/ar-transport.c
7.07 KB
17926a793 [AF_RXRPC]: Provi... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
/* RxRPC point-to-point transport session management * * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ #include <linux/module.h> #include <linux/net.h> #include <linux/skbuff.h> |
5a0e3ad6a include cleanup: ... |
15 |
#include <linux/slab.h> |
17926a793 [AF_RXRPC]: Provi... |
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
#include <net/sock.h> #include <net/af_rxrpc.h> #include "ar-internal.h" static void rxrpc_transport_reaper(struct work_struct *work); static LIST_HEAD(rxrpc_transports); static DEFINE_RWLOCK(rxrpc_transport_lock); static unsigned long rxrpc_transport_timeout = 3600 * 24; static DECLARE_DELAYED_WORK(rxrpc_transport_reap, rxrpc_transport_reaper); /* * allocate a new transport session manager */ static struct rxrpc_transport *rxrpc_alloc_transport(struct rxrpc_local *local, struct rxrpc_peer *peer, gfp_t gfp) { struct rxrpc_transport *trans; _enter(""); trans = kzalloc(sizeof(struct rxrpc_transport), gfp); if (trans) { trans->local = local; trans->peer = peer; INIT_LIST_HEAD(&trans->link); trans->bundles = RB_ROOT; trans->client_conns = RB_ROOT; trans->server_conns = RB_ROOT; skb_queue_head_init(&trans->error_queue); spin_lock_init(&trans->client_lock); rwlock_init(&trans->conn_lock); atomic_set(&trans->usage, 1); trans->debug_id = atomic_inc_return(&rxrpc_debug_id); if (peer->srx.transport.family == AF_INET) { switch (peer->srx.transport_type) { case SOCK_DGRAM: INIT_WORK(&trans->error_handler, rxrpc_UDP_error_handler); break; default: BUG(); break; } } else { BUG(); } } _leave(" = %p", trans); return trans; } /* * obtain a transport session for the nominated endpoints */ struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *local, struct rxrpc_peer *peer, gfp_t gfp) { struct rxrpc_transport *trans, *candidate; const char *new = "old"; int usage; |
21454aaad net: replace NIPQ... |
81 82 |
_enter("{%pI4+%hu},{%pI4+%hu},", &local->srx.transport.sin.sin_addr, |
17926a793 [AF_RXRPC]: Provi... |
83 |
ntohs(local->srx.transport.sin.sin_port), |
21454aaad net: replace NIPQ... |
84 |
&peer->srx.transport.sin.sin_addr, |
17926a793 [AF_RXRPC]: Provi... |
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
ntohs(peer->srx.transport.sin.sin_port)); /* search the transport list first */ read_lock_bh(&rxrpc_transport_lock); list_for_each_entry(trans, &rxrpc_transports, link) { if (trans->local == local && trans->peer == peer) goto found_extant_transport; } read_unlock_bh(&rxrpc_transport_lock); /* not yet present - create a candidate for a new record and then * redo the search */ candidate = rxrpc_alloc_transport(local, peer, gfp); if (!candidate) { _leave(" = -ENOMEM"); return ERR_PTR(-ENOMEM); } write_lock_bh(&rxrpc_transport_lock); list_for_each_entry(trans, &rxrpc_transports, link) { if (trans->local == local && trans->peer == peer) goto found_extant_second; } /* we can now add the new candidate to the list */ trans = candidate; candidate = NULL; |
ed84cadb2 rxrpc: Fix set bu... |
113 |
usage = atomic_read(&trans->usage); |
17926a793 [AF_RXRPC]: Provi... |
114 115 116 117 118 119 120 121 122 123 124 125 126 |
rxrpc_get_local(trans->local); atomic_inc(&trans->peer->usage); list_add_tail(&trans->link, &rxrpc_transports); write_unlock_bh(&rxrpc_transport_lock); new = "new"; success: _net("TRANSPORT %s %d local %d -> peer %d", new, trans->debug_id, trans->local->debug_id, trans->peer->debug_id); |
ed84cadb2 rxrpc: Fix set bu... |
127 |
_leave(" = %p {u=%d}", trans, usage); |
17926a793 [AF_RXRPC]: Provi... |
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
return trans; /* we found the transport in the list immediately */ found_extant_transport: usage = atomic_inc_return(&trans->usage); read_unlock_bh(&rxrpc_transport_lock); goto success; /* we found the transport on the second time through the list */ found_extant_second: usage = atomic_inc_return(&trans->usage); write_unlock_bh(&rxrpc_transport_lock); kfree(candidate); goto success; } /* * find the transport connecting two endpoints */ struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *local, struct rxrpc_peer *peer) { struct rxrpc_transport *trans; |
21454aaad net: replace NIPQ... |
151 152 |
_enter("{%pI4+%hu},{%pI4+%hu},", &local->srx.transport.sin.sin_addr, |
17926a793 [AF_RXRPC]: Provi... |
153 |
ntohs(local->srx.transport.sin.sin_port), |
21454aaad net: replace NIPQ... |
154 |
&peer->srx.transport.sin.sin_addr, |
17926a793 [AF_RXRPC]: Provi... |
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
ntohs(peer->srx.transport.sin.sin_port)); /* search the transport list */ read_lock_bh(&rxrpc_transport_lock); list_for_each_entry(trans, &rxrpc_transports, link) { if (trans->local == local && trans->peer == peer) goto found_extant_transport; } read_unlock_bh(&rxrpc_transport_lock); _leave(" = NULL"); return NULL; found_extant_transport: atomic_inc(&trans->usage); read_unlock_bh(&rxrpc_transport_lock); _leave(" = %p", trans); return trans; } /* * release a transport session */ void rxrpc_put_transport(struct rxrpc_transport *trans) { _enter("%p{u=%d}", trans, atomic_read(&trans->usage)); ASSERTCMP(atomic_read(&trans->usage), >, 0); |
2c6b47de1 Cleanup non-arch ... |
184 |
trans->put_time = get_seconds(); |
50aab54f3 net: Add missing ... |
185 |
if (unlikely(atomic_dec_and_test(&trans->usage))) { |
17926a793 [AF_RXRPC]: Provi... |
186 187 188 189 |
_debug("zombie"); /* let the reaper determine the timeout to avoid a race with * overextending the timeout if the reaper is running at the * same time */ |
651350d10 [AF_RXRPC]: Add a... |
190 |
rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0); |
50aab54f3 net: Add missing ... |
191 |
} |
17926a793 [AF_RXRPC]: Provi... |
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
_leave(""); } /* * clean up a transport session */ static void rxrpc_cleanup_transport(struct rxrpc_transport *trans) { _net("DESTROY TRANS %d", trans->debug_id); rxrpc_purge_queue(&trans->error_queue); rxrpc_put_local(trans->local); rxrpc_put_peer(trans->peer); kfree(trans); } /* * reap dead transports that have passed their expiry date */ static void rxrpc_transport_reaper(struct work_struct *work) { struct rxrpc_transport *trans, *_p; unsigned long now, earliest, reap_time; LIST_HEAD(graveyard); _enter(""); |
2c6b47de1 Cleanup non-arch ... |
220 |
now = get_seconds(); |
17926a793 [AF_RXRPC]: Provi... |
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 |
earliest = ULONG_MAX; /* extract all the transports that have been dead too long */ write_lock_bh(&rxrpc_transport_lock); list_for_each_entry_safe(trans, _p, &rxrpc_transports, link) { _debug("reap TRANS %d { u=%d t=%ld }", trans->debug_id, atomic_read(&trans->usage), (long) now - (long) trans->put_time); if (likely(atomic_read(&trans->usage) > 0)) continue; reap_time = trans->put_time + rxrpc_transport_timeout; if (reap_time <= now) list_move_tail(&trans->link, &graveyard); else if (reap_time < earliest) earliest = reap_time; } write_unlock_bh(&rxrpc_transport_lock); if (earliest != ULONG_MAX) { _debug("reschedule reaper %ld", (long) earliest - now); ASSERTCMP(earliest, >, now); |
651350d10 [AF_RXRPC]: Add a... |
244 245 |
rxrpc_queue_delayed_work(&rxrpc_transport_reap, (earliest - now) * HZ); |
17926a793 [AF_RXRPC]: Provi... |
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
} /* then destroy all those pulled out */ while (!list_empty(&graveyard)) { trans = list_entry(graveyard.next, struct rxrpc_transport, link); list_del_init(&trans->link); ASSERTCMP(atomic_read(&trans->usage), ==, 0); rxrpc_cleanup_transport(trans); } _leave(""); } /* * preemptively destroy all the transport session records rather than waiting * for them to time out */ void __exit rxrpc_destroy_all_transports(void) { _enter(""); rxrpc_transport_timeout = 0; cancel_delayed_work(&rxrpc_transport_reap); |
651350d10 [AF_RXRPC]: Add a... |
271 |
rxrpc_queue_delayed_work(&rxrpc_transport_reap, 0); |
17926a793 [AF_RXRPC]: Provi... |
272 273 274 |
_leave(""); } |