// SPDX-License-Identifier: GPL-2.0-or-later /* RxRPC virtual connection handler, common bits. * * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
/* * Time till a connection expires after last use (in seconds).
*/ unsignedint __read_mostly rxrpc_connection_expiry = 10 * 60; unsignedint __read_mostly rxrpc_closed_conn_expiry = 10;
/* * Look up a connection in the cache by protocol parameters. * * If successful, a pointer to the connection is returned, but no ref is taken. * NULL is returned if there is no match. * * When searching for a service call, if we find a peer but no connection, we * return that through *_peer in case we need to create a new service call. * * The caller must be holding the RCU read lock.
*/ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *local, struct sockaddr_rxrpc *srx, struct sk_buff *skb)
{ struct rxrpc_connection *conn; struct rxrpc_skb_priv *sp = rxrpc_skb(skb); struct rxrpc_peer *peer;
_enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
/* Look up client connections by connection ID alone as their * IDs are unique for this machine.
*/
conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT); if (!conn || refcount_read(&conn->ref) == 0) {
_debug("no conn"); goto not_found;
}
if (conn->proto.epoch != sp->hdr.epoch ||
conn->local != local) goto not_found;
peer = conn->peer; switch (srx->transport.family) { case AF_INET: if (peer->srx.transport.sin.sin_port !=
srx->transport.sin.sin_port) goto not_found; break; #ifdef CONFIG_AF_RXRPC_IPV6 case AF_INET6: if (peer->srx.transport.sin6.sin6_port !=
srx->transport.sin6.sin6_port) goto not_found; break; #endif default:
BUG();
}
_leave(" = %p", conn); return conn;
not_found:
_leave(" = NULL"); return NULL;
}
/* * Disconnect a call and clear any channel it occupies when that call * terminates. The caller must hold the channel_lock and must release the * call's ref on the connection.
*/ void __rxrpc_disconnect_call(struct rxrpc_connection *conn, struct rxrpc_call *call)
{ struct rxrpc_channel *chan =
&conn->channels[call->cid & RXRPC_CHANNELMASK];
_enter("%d,%x", conn->debug_id, call->cid);
if (chan->call == call) { /* Save the result of the call so that we can repeat it if necessary * through the channel, whilst disposing of the actual call record.
*/
trace_rxrpc_disconnect_call(call); switch (call->completion) { case RXRPC_CALL_SUCCEEDED:
chan->last_seq = call->rx_highest_seq;
chan->last_type = RXRPC_PACKET_TYPE_ACK; break; case RXRPC_CALL_LOCALLY_ABORTED:
chan->last_abort = call->abort_code;
chan->last_type = RXRPC_PACKET_TYPE_ABORT; break; default:
chan->last_abort = RX_CALL_DEAD;
chan->last_type = RXRPC_PACKET_TYPE_ABORT; break;
}
/* * Disconnect a call and clear any channel it occupies when that call * terminates.
*/ void rxrpc_disconnect_call(struct rxrpc_call *call)
{ struct rxrpc_connection *conn = call->conn;
/* * Queue a connection's work processor, getting a ref to pass to the work * queue.
*/ void rxrpc_queue_conn(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{ if (atomic_read(&conn->active) >= 0 &&
rxrpc_queue_work(&conn->processor))
rxrpc_see_connection(conn, why);
}
/* * Note the re-emergence of a connection.
*/ void rxrpc_see_connection(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{ if (conn) { int r = refcount_read(&conn->ref);
trace_rxrpc_conn(conn->debug_id, r, why);
}
}
/* * Get a ref on a connection.
*/ struct rxrpc_connection *rxrpc_get_connection(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{ int r;
__refcount_inc(&conn->ref, &r);
trace_rxrpc_conn(conn->debug_id, r + 1, why); return conn;
}
/* * Try to get a ref on a connection.
*/ struct rxrpc_connection *
rxrpc_get_connection_maybe(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{ int r;
if (conn) { if (__refcount_inc_not_zero(&conn->ref, &r))
trace_rxrpc_conn(conn->debug_id, r + 1, why); else
conn = NULL;
} return conn;
}
/* * Set the service connection reap timer.
*/ staticvoid rxrpc_set_service_reap_timer(struct rxrpc_net *rxnet, unsignedlong reap_at)
{ if (rxnet->live)
timer_reduce(&rxnet->service_conn_reap_timer, reap_at);
}
/* Drain the Rx queue. Note that even though we've unpublished, an * incoming packet could still be being added to our Rx queue, so we * will need to drain it again in the RCU cleanup handler.
*/
rxrpc_purge_queue(&conn->rx_queue);
/* * Drop a ref on a connection.
*/ void rxrpc_put_connection(struct rxrpc_connection *conn, enum rxrpc_conn_trace why)
{ unsignedint debug_id; bool dead; int r;
if (!conn) return;
debug_id = conn->debug_id;
dead = __refcount_dec_and_test(&conn->ref, &r);
trace_rxrpc_conn(debug_id, r - 1, why); if (dead) {
timer_delete(&conn->timer);
cancel_work(&conn->processor);
if (in_softirq() || work_busy(&conn->processor) ||
timer_pending(&conn->timer)) /* Can't use the rxrpc workqueue as we need to cancel/flush * something that may be running/waiting there.
*/
schedule_work(&conn->destructor); else
rxrpc_clean_up_connection(&conn->destructor);
}
}
if (time_before(now, expire_at)) { if (time_before(expire_at, earliest))
earliest = expire_at; continue;
}
}
/* The activity count sits at 0 whilst the conn is unused on * the list; we reduce that to -1 to make the conn unavailable.
*/
active = 0; if (!atomic_try_cmpxchg(&conn->active, &active, -1)) continue;
rxrpc_see_connection(conn, rxrpc_conn_see_reap_service);
if (rxrpc_conn_is_client(conn))
BUG(); else
rxrpc_unpublish_service_conn(conn);
/* * preemptively destroy all the service connection records rather than * waiting for them to time out
*/ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
{ struct rxrpc_connection *conn, *_p; bool leak = false;
/* We need to wait for the connections to be destroyed by RCU as they * pin things that we still need to get rid of.
*/
wait_var_event(&rxnet->nr_conns, !atomic_read(&rxnet->nr_conns));
_leave("");
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.