rxrpc: Make the set of connection IDs per local endpoint
Make the set of connection IDs per local endpoint so that endpoints don't cause each other's connections to get dismissed. Signed-off-by: David Howells <dhowells@redhat.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: linux-afs@lists.infradead.org
This commit is contained in:
Родитель
57af281e53
Коммит
f06cb29189
|
@ -957,16 +957,9 @@ static const struct net_proto_family rxrpc_family_ops = {
|
|||
static int __init af_rxrpc_init(void)
|
||||
{
|
||||
int ret = -1;
|
||||
unsigned int tmp;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct rxrpc_skb_priv) > sizeof_field(struct sk_buff, cb));
|
||||
|
||||
get_random_bytes(&tmp, sizeof(tmp));
|
||||
tmp &= 0x3fffffff;
|
||||
if (tmp == 0)
|
||||
tmp = 1;
|
||||
idr_set_cursor(&rxrpc_client_conn_ids, tmp);
|
||||
|
||||
ret = -ENOMEM;
|
||||
rxrpc_call_jar = kmem_cache_create(
|
||||
"rxrpc_call_jar", sizeof(struct rxrpc_call), 0,
|
||||
|
@ -1062,7 +1055,6 @@ static void __exit af_rxrpc_exit(void)
|
|||
* are released.
|
||||
*/
|
||||
rcu_barrier();
|
||||
rxrpc_destroy_client_conn_ids();
|
||||
|
||||
destroy_workqueue(rxrpc_workqueue);
|
||||
rxrpc_exit_security();
|
||||
|
|
|
@ -300,6 +300,8 @@ struct rxrpc_local {
|
|||
int debug_id; /* debug ID for printks */
|
||||
bool dead;
|
||||
bool service_closed; /* Service socket closed */
|
||||
struct idr conn_ids; /* List of connection IDs */
|
||||
spinlock_t conn_lock; /* Lock for client connection pool */
|
||||
struct sockaddr_rxrpc srx; /* local address */
|
||||
};
|
||||
|
||||
|
@ -887,9 +889,8 @@ static inline bool rxrpc_is_client_call(const struct rxrpc_call *call)
|
|||
extern unsigned int rxrpc_reap_client_connections;
|
||||
extern unsigned long rxrpc_conn_idle_client_expiry;
|
||||
extern unsigned long rxrpc_conn_idle_client_fast_expiry;
|
||||
extern struct idr rxrpc_client_conn_ids;
|
||||
|
||||
void rxrpc_destroy_client_conn_ids(void);
|
||||
void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local);
|
||||
struct rxrpc_bundle *rxrpc_get_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
|
||||
void rxrpc_put_bundle(struct rxrpc_bundle *, enum rxrpc_bundle_trace);
|
||||
int rxrpc_connect_call(struct rxrpc_sock *, struct rxrpc_call *,
|
||||
|
|
|
@ -34,12 +34,6 @@ __read_mostly unsigned int rxrpc_reap_client_connections = 900;
|
|||
__read_mostly unsigned long rxrpc_conn_idle_client_expiry = 2 * 60 * HZ;
|
||||
__read_mostly unsigned long rxrpc_conn_idle_client_fast_expiry = 2 * HZ;
|
||||
|
||||
/*
|
||||
* We use machine-unique IDs for our client connections.
|
||||
*/
|
||||
DEFINE_IDR(rxrpc_client_conn_ids);
|
||||
static DEFINE_SPINLOCK(rxrpc_conn_id_lock);
|
||||
|
||||
static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
|
||||
|
||||
/*
|
||||
|
@ -51,65 +45,65 @@ static void rxrpc_deactivate_bundle(struct rxrpc_bundle *bundle);
|
|||
static int rxrpc_get_client_connection_id(struct rxrpc_connection *conn,
|
||||
gfp_t gfp)
|
||||
{
|
||||
struct rxrpc_net *rxnet = conn->rxnet;
|
||||
struct rxrpc_local *local = conn->local;
|
||||
int id;
|
||||
|
||||
_enter("");
|
||||
|
||||
idr_preload(gfp);
|
||||
spin_lock(&rxrpc_conn_id_lock);
|
||||
spin_lock(&local->conn_lock);
|
||||
|
||||
id = idr_alloc_cyclic(&rxrpc_client_conn_ids, conn,
|
||||
id = idr_alloc_cyclic(&local->conn_ids, conn,
|
||||
1, 0x40000000, GFP_NOWAIT);
|
||||
if (id < 0)
|
||||
goto error;
|
||||
|
||||
spin_unlock(&rxrpc_conn_id_lock);
|
||||
spin_unlock(&local->conn_lock);
|
||||
idr_preload_end();
|
||||
|
||||
conn->proto.epoch = rxnet->epoch;
|
||||
conn->proto.epoch = local->rxnet->epoch;
|
||||
conn->proto.cid = id << RXRPC_CIDSHIFT;
|
||||
set_bit(RXRPC_CONN_HAS_IDR, &conn->flags);
|
||||
_leave(" [CID %x]", conn->proto.cid);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
spin_unlock(&rxrpc_conn_id_lock);
|
||||
spin_unlock(&local->conn_lock);
|
||||
idr_preload_end();
|
||||
_leave(" = %d", id);
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Release a connection ID for a client connection from the global pool.
|
||||
* Release a connection ID for a client connection.
|
||||
*/
|
||||
static void rxrpc_put_client_connection_id(struct rxrpc_connection *conn)
|
||||
static void rxrpc_put_client_connection_id(struct rxrpc_local *local,
|
||||
struct rxrpc_connection *conn)
|
||||
{
|
||||
if (test_bit(RXRPC_CONN_HAS_IDR, &conn->flags)) {
|
||||
spin_lock(&rxrpc_conn_id_lock);
|
||||
idr_remove(&rxrpc_client_conn_ids,
|
||||
conn->proto.cid >> RXRPC_CIDSHIFT);
|
||||
spin_unlock(&rxrpc_conn_id_lock);
|
||||
spin_lock(&local->conn_lock);
|
||||
idr_remove(&local->conn_ids, conn->proto.cid >> RXRPC_CIDSHIFT);
|
||||
spin_unlock(&local->conn_lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy the client connection ID tree.
|
||||
*/
|
||||
void rxrpc_destroy_client_conn_ids(void)
|
||||
void rxrpc_destroy_client_conn_ids(struct rxrpc_local *local)
|
||||
{
|
||||
struct rxrpc_connection *conn;
|
||||
int id;
|
||||
|
||||
if (!idr_is_empty(&rxrpc_client_conn_ids)) {
|
||||
idr_for_each_entry(&rxrpc_client_conn_ids, conn, id) {
|
||||
if (!idr_is_empty(&local->conn_ids)) {
|
||||
idr_for_each_entry(&local->conn_ids, conn, id) {
|
||||
pr_err("AF_RXRPC: Leaked client conn %p {%d}\n",
|
||||
conn, refcount_read(&conn->ref));
|
||||
}
|
||||
BUG();
|
||||
}
|
||||
|
||||
idr_destroy(&rxrpc_client_conn_ids);
|
||||
idr_destroy(&local->conn_ids);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -225,7 +219,7 @@ rxrpc_alloc_client_connection(struct rxrpc_bundle *bundle, gfp_t gfp)
|
|||
return conn;
|
||||
|
||||
error_1:
|
||||
rxrpc_put_client_connection_id(conn);
|
||||
rxrpc_put_client_connection_id(bundle->local, conn);
|
||||
error_0:
|
||||
kfree(conn);
|
||||
_leave(" = %d", ret);
|
||||
|
@ -257,7 +251,7 @@ static bool rxrpc_may_reuse_conn(struct rxrpc_connection *conn)
|
|||
* times the maximum number of client conns away from the current
|
||||
* allocation point to try and keep the IDs concentrated.
|
||||
*/
|
||||
id_cursor = idr_get_cursor(&rxrpc_client_conn_ids);
|
||||
id_cursor = idr_get_cursor(&conn->local->conn_ids);
|
||||
id = conn->proto.cid >> RXRPC_CIDSHIFT;
|
||||
distance = id - id_cursor;
|
||||
if (distance < 0)
|
||||
|
@ -982,7 +976,7 @@ void rxrpc_kill_client_conn(struct rxrpc_connection *conn)
|
|||
trace_rxrpc_client(conn, -1, rxrpc_client_cleanup);
|
||||
atomic_dec(&rxnet->nr_client_conns);
|
||||
|
||||
rxrpc_put_client_connection_id(conn);
|
||||
rxrpc_put_client_connection_id(local, conn);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -100,10 +100,10 @@ struct rxrpc_connection *rxrpc_find_client_connection_rcu(struct rxrpc_local *lo
|
|||
|
||||
_enter(",%x", sp->hdr.cid & RXRPC_CIDMASK);
|
||||
|
||||
/* Look up client connections by connection ID alone as their IDs are
|
||||
* unique for this machine.
|
||||
/* Look up client connections by connection ID alone as their
|
||||
* IDs are unique for this machine.
|
||||
*/
|
||||
conn = idr_find(&rxrpc_client_conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
|
||||
conn = idr_find(&local->conn_ids, sp->hdr.cid >> RXRPC_CIDSHIFT);
|
||||
if (!conn || refcount_read(&conn->ref) == 0) {
|
||||
_debug("no conn");
|
||||
goto not_found;
|
||||
|
|
|
@ -89,6 +89,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
|
|||
const struct sockaddr_rxrpc *srx)
|
||||
{
|
||||
struct rxrpc_local *local;
|
||||
u32 tmp;
|
||||
|
||||
local = kzalloc(sizeof(struct rxrpc_local), GFP_KERNEL);
|
||||
if (local) {
|
||||
|
@ -109,6 +110,14 @@ static struct rxrpc_local *rxrpc_alloc_local(struct net *net,
|
|||
local->debug_id = atomic_inc_return(&rxrpc_debug_id);
|
||||
memcpy(&local->srx, srx, sizeof(*srx));
|
||||
local->srx.srx_service = 0;
|
||||
idr_init(&local->conn_ids);
|
||||
get_random_bytes(&tmp, sizeof(tmp));
|
||||
tmp &= 0x3fffffff;
|
||||
if (tmp == 0)
|
||||
tmp = 1;
|
||||
idr_set_cursor(&local->conn_ids, tmp);
|
||||
spin_lock_init(&local->conn_lock);
|
||||
|
||||
trace_rxrpc_local(local->debug_id, rxrpc_local_new, 1, 1);
|
||||
}
|
||||
|
||||
|
@ -409,6 +418,7 @@ void rxrpc_destroy_local(struct rxrpc_local *local)
|
|||
* local endpoint.
|
||||
*/
|
||||
rxrpc_purge_queue(&local->rx_queue);
|
||||
rxrpc_destroy_client_conn_ids(local);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче