diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h index cc51d3eb0548cd4b43cbb9f9f5fd7d0d84dfc537..d40d54b785676aa75bac22328fbb410c0ea9fe82 100644 --- a/net/rxrpc/ar-internal.h +++ b/net/rxrpc/ar-internal.h @@ -77,6 +77,7 @@ struct rxrpc_net { rwlock_t call_lock; /* Lock for ->calls */ atomic_t nr_calls; /* Count of allocated calls */ + atomic_t nr_conns; struct list_head conn_proc_list; /* List of conns in this namespace for proc */ struct list_head service_conns; /* Service conns in this namespace */ rwlock_t conn_lock; /* Lock for ->conn_proc_list, ->service_conns */ diff --git a/net/rxrpc/call_accept.c b/net/rxrpc/call_accept.c index 5a9b1d91612462cf6f0bb8470897db305f7130ac..f67017dcb25e00cc9e595d3e0c1824d0b15d63ae 100644 --- a/net/rxrpc/call_accept.c +++ b/net/rxrpc/call_accept.c @@ -219,6 +219,8 @@ void rxrpc_discard_prealloc(struct rxrpc_sock *rx) list_del(&conn->proc_link); write_unlock(&rxnet->conn_lock); kfree(conn); + if (atomic_dec_and_test(&rxnet->nr_conns)) + wake_up_atomic_t(&rxnet->nr_conns); tail = (tail + 1) & (size - 1); } diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c index 041da40dbf936d20f37b61cc12fc6803a4125524..5736f643c51646b603cbad57330930bba6712ff1 100644 --- a/net/rxrpc/conn_client.c +++ b/net/rxrpc/conn_client.c @@ -207,6 +207,7 @@ rxrpc_alloc_client_connection(struct rxrpc_conn_parameters *cp, gfp_t gfp) if (ret < 0) goto error_2; + atomic_inc(&rxnet->nr_conns); write_lock(&rxnet->conn_lock); list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); write_unlock(&rxnet->conn_lock); diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c index bfc46fd69a621d6d25e5548223578f642e2e0347..0950ee3d26f56918b8dbb1ef3b1925c8755776bf 100644 --- a/net/rxrpc/conn_object.c +++ b/net/rxrpc/conn_object.c @@ -365,6 +365,9 @@ static void rxrpc_destroy_connection(struct rcu_head *rcu) key_put(conn->params.key); key_put(conn->server_key); rxrpc_put_peer(conn->params.peer); + + if (atomic_dec_and_test(&conn->params.local->rxnet->nr_conns)) + wake_up_atomic_t(&conn->params.local->rxnet->nr_conns); rxrpc_put_local(conn->params.local); kfree(conn); @@ -458,6 +461,7 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet) _enter(""); + atomic_dec(&rxnet->nr_conns); rxrpc_destroy_all_client_connections(rxnet); del_timer_sync(&rxnet->service_conn_reap_timer); @@ -475,5 +479,9 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet) ASSERT(list_empty(&rxnet->conn_proc_list)); + /* 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_on_atomic_t(&rxnet->nr_conns, atomic_t_wait, TASK_UNINTERRUPTIBLE); _leave(""); } diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c index f6fcdb3130a19a9bcb74b2d7dd5af7886ed8912d..80773a50c755168773c758cb5c2b5b86c117cf02 100644 --- a/net/rxrpc/conn_service.c +++ b/net/rxrpc/conn_service.c @@ -132,6 +132,7 @@ struct rxrpc_connection *rxrpc_prealloc_service_connection(struct rxrpc_net *rxn conn->state = RXRPC_CONN_SERVICE_PREALLOC; atomic_set(&conn->usage, 2); + atomic_inc(&rxnet->nr_conns); write_lock(&rxnet->conn_lock); list_add_tail(&conn->link, &rxnet->service_conns); list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); diff --git a/net/rxrpc/net_ns.c b/net/rxrpc/net_ns.c index 101019b0be34bf7c25955b63d32713d7ac0f51fd..fa9ce60e7bfa598029e6de402111f94281071381 100644 --- a/net/rxrpc/net_ns.c +++ b/net/rxrpc/net_ns.c @@ -57,6 +57,7 @@ static __net_init int rxrpc_init_net(struct net *net) rwlock_init(&rxnet->call_lock); atomic_set(&rxnet->nr_calls, 1); + atomic_set(&rxnet->nr_conns, 1); INIT_LIST_HEAD(&rxnet->conn_proc_list); INIT_LIST_HEAD(&rxnet->service_conns); rwlock_init(&rxnet->conn_lock);