// SPDX-License-Identifier: GPL-2.0-or-later /* RxRPC remote transport endpoint record management * * Copyright (C) 2007, 2016 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com)
*/
switch (srx->transport.family) { case AF_INET:
hash_key += (u16 __force)srx->transport.sin.sin_port;
size = sizeof(srx->transport.sin.sin_addr);
p = (u16 *)&srx->transport.sin.sin_addr; break; #ifdef CONFIG_AF_RXRPC_IPV6 case AF_INET6:
hash_key += (u16 __force)srx->transport.sin.sin_port;
size = sizeof(srx->transport.sin6.sin6_addr);
p = (u16 *)&srx->transport.sin6.sin6_addr; break; #endif default:
WARN(1, "AF_RXRPC: Unsupported transport address family\n"); return 0;
}
/* Step through the peer address in 16-bit portions for speed */ for (i = 0; i < size; i += sizeof(*p), p++)
hash_key += *p;
_leave(" 0x%lx", hash_key); return hash_key;
}
/* * Compare a peer to a key. Return -ve, 0 or +ve to indicate less than, same * or greater than. * * Unfortunately, the primitives in linux/hashtable.h don't allow for sorted * buckets and mid-bucket insertion, so we don't make full use of this * information at this point.
*/ staticlong rxrpc_peer_cmp_key(conststruct rxrpc_peer *peer, struct rxrpc_local *local, conststruct sockaddr_rxrpc *srx, unsignedlong hash_key)
{ long diff;
/* * Set up a new incoming peer. There shouldn't be any other matching peers * since we've already done a search in the list from the non-reentrant context * (the data_ready handler) that is the only place we can add new peers. * Called with interrupts disabled.
*/ void rxrpc_new_incoming_peer(struct rxrpc_local *local, struct rxrpc_peer *peer)
{ struct rxrpc_net *rxnet = local->rxnet; unsignedlong hash_key;
/* * obtain a remote transport endpoint for the specified address
*/ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local, struct sockaddr_rxrpc *srx, gfp_t gfp)
{ struct rxrpc_peer *peer, *candidate; struct rxrpc_net *rxnet = local->rxnet; unsignedlong hash_key = rxrpc_peer_hash_key(local, srx);
_enter("{%pISp}", &srx->transport);
/* search the peer list first */
rcu_read_lock();
peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_lookup_client))
peer = NULL;
rcu_read_unlock();
if (!peer) { /* The peer is not yet present in hash - create a candidate * for a new record and then redo the search.
*/
candidate = rxrpc_create_peer(local, srx, hash_key, gfp); if (!candidate) {
_leave(" = NULL [nomem]"); return NULL;
}
spin_lock_bh(&rxnet->peer_hash_lock);
/* Need to check that we aren't racing with someone else */
peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key); if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_lookup_client))
peer = NULL; if (!peer) {
hash_add_rcu(rxnet->peer_hash,
&candidate->hash_link, hash_key);
list_add_tail(&candidate->keepalive_link,
&rxnet->peer_keepalive_new);
}
spin_unlock_bh(&rxnet->peer_hash_lock);
if (peer)
rxrpc_free_peer(candidate); else
peer = candidate;
}
/* * Get a ref on a peer record.
*/ struct rxrpc_peer *rxrpc_get_peer(struct rxrpc_peer *peer, enum rxrpc_peer_trace why)
{ int r;
__refcount_inc(&peer->ref, &r);
trace_rxrpc_peer(peer->debug_id, r + 1, why); return peer;
}
/* * Get a ref on a peer record unless its usage has already reached 0.
*/ struct rxrpc_peer *rxrpc_get_peer_maybe(struct rxrpc_peer *peer, enum rxrpc_peer_trace why)
{ int r;
if (peer) { if (__refcount_inc_not_zero(&peer->ref, &r))
trace_rxrpc_peer(peer->debug_id, r + 1, why); else
peer = NULL;
} return peer;
}
/* * Drop a ref on a peer record.
*/ void rxrpc_put_peer(struct rxrpc_peer *peer, enum rxrpc_peer_trace why)
{ unsignedint debug_id; bool dead; int r;
if (peer) {
debug_id = peer->debug_id;
dead = __refcount_dec_and_test(&peer->ref, &r);
trace_rxrpc_peer(debug_id, r - 1, why); if (dead)
__rxrpc_put_peer(peer);
}
}
/* * Make sure all peer records have been discarded.
*/ void rxrpc_destroy_all_peers(struct rxrpc_net *rxnet)
{ struct rxrpc_peer *peer; int i;
for (i = 0; i < HASH_SIZE(rxnet->peer_hash); i++) { if (hlist_empty(&rxnet->peer_hash[i])) continue;
/** * rxrpc_kernel_get_call_peer - Get the peer address of a call * @sock: The socket on which the call is in progress. * @call: The call to query * * Get a record for the remote peer in a call. * * Return: The call's peer record.
*/ struct rxrpc_peer *rxrpc_kernel_get_call_peer(struct socket *sock, struct rxrpc_call *call)
{ return rxrpc_get_peer(call->peer, rxrpc_peer_get_application);
}
EXPORT_SYMBOL(rxrpc_kernel_get_call_peer);
/** * rxrpc_kernel_get_srtt - Get a call's peer smoothed RTT * @peer: The peer to query * * Get the call's peer smoothed RTT. * * Return: The RTT in uS or %UINT_MAX if we have no samples.
*/ unsignedint rxrpc_kernel_get_srtt(conststruct rxrpc_peer *peer)
{ return READ_ONCE(peer->recent_srtt_us);
}
EXPORT_SYMBOL(rxrpc_kernel_get_srtt);
/** * rxrpc_kernel_remote_srx - Get the address of a peer * @peer: The peer to query * * Get a pointer to the address from a peer record. The caller is responsible * for making sure that the address is not deallocated. A fake address will be * substituted if %peer in NULL. * * Return: The rxrpc address record or a fake record.
*/ conststruct sockaddr_rxrpc *rxrpc_kernel_remote_srx(conststruct rxrpc_peer *peer)
{ return peer ? &peer->srx : &rxrpc_null_addr;
}
EXPORT_SYMBOL(rxrpc_kernel_remote_srx);
/** * rxrpc_kernel_remote_addr - Get the peer transport address of a call * @peer: The peer to query * * Get a pointer to the transport address from a peer record. The caller is * responsible for making sure that the address is not deallocated. A fake * address will be substituted if %peer in NULL. * * Return: The transport address record or a fake record.
*/ conststruct sockaddr *rxrpc_kernel_remote_addr(conststruct rxrpc_peer *peer)
{ return (conststruct sockaddr *)
(peer ? &peer->srx.transport : &rxrpc_null_addr.transport);
}
EXPORT_SYMBOL(rxrpc_kernel_remote_addr);
/** * rxrpc_kernel_set_peer_data - Set app-specific data on a peer. * @peer: The peer to alter * @app_data: The data to set * * Set the app-specific data on a peer. AF_RXRPC makes no effort to retain * anything the data might refer to. * * Return: The previous app_data.
*/ unsignedlong rxrpc_kernel_set_peer_data(struct rxrpc_peer *peer, unsignedlong app_data)
{ return xchg(&peer->app_data, app_data);
}
EXPORT_SYMBOL(rxrpc_kernel_set_peer_data);
/** * rxrpc_kernel_get_peer_data - Get app-specific data from a peer. * @peer: The peer to query * * Retrieve the app-specific data from a peer. * * Return: The peer's app data.
*/ unsignedlong rxrpc_kernel_get_peer_data(conststruct rxrpc_peer *peer)
{ return peer->app_data;
}
EXPORT_SYMBOL(rxrpc_kernel_get_peer_data);
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.