aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2018-03-30 16:05:33 -0400
committerDavid Howells <dhowells@redhat.com>2018-03-30 16:05:33 -0400
commit31f5f9a1691ebef2113c8bdb3edcb8859f30f702 (patch)
tree20de5ce61ea1a3aad4e58426e24b038203c53af8
parent09d2bf595db4b4075ea721acd61e180d6bb18f88 (diff)
rxrpc: Fix apparent leak of rxrpc_local objects
rxrpc_local objects cannot be disposed of until all the connections that point to them have been RCU'd as a connection object holds refcount on the local endpoint it is communicating through. Currently, this can cause an assertion failure to occur when a network namespace is destroyed as there's no check that the RCU destructors for the connections have been run before we start trying to destroy local endpoints. The kernel reports: rxrpc: AF_RXRPC: Leaked local 0000000036a41bc1 {5} ------------[ cut here ]------------ kernel BUG at ../net/rxrpc/local_object.c:439! Fix this by keeping a count of the live connections and waiting for it to go to zero at the end of rxrpc_destroy_all_connections(). Fixes: dee46364ce6f ("rxrpc: Add RCU destruction for connections and calls") Signed-off-by: David Howells <dhowells@redhat.com>
-rw-r--r--net/rxrpc/ar-internal.h1
-rw-r--r--net/rxrpc/call_accept.c2
-rw-r--r--net/rxrpc/conn_client.c1
-rw-r--r--net/rxrpc/conn_object.c8
-rw-r--r--net/rxrpc/conn_service.c1
-rw-r--r--net/rxrpc/net_ns.c1
6 files changed, 14 insertions, 0 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index cc51d3eb0548..d40d54b78567 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -77,6 +77,7 @@ struct rxrpc_net {
77 rwlock_t call_lock; /* Lock for ->calls */ 77 rwlock_t call_lock; /* Lock for ->calls */
78 atomic_t nr_calls; /* Count of allocated calls */ 78 atomic_t nr_calls; /* Count of allocated calls */
79 79
80 atomic_t nr_conns;
80 struct list_head conn_proc_list; /* List of conns in this namespace for proc */ 81 struct list_head conn_proc_list; /* List of conns in this namespace for proc */
81 struct list_head service_conns; /* Service conns in this namespace */ 82 struct list_head service_conns; /* Service conns in this namespace */
82 rwlock_t conn_lock; /* Lock for ->conn_proc_list, ->service_conns */ 83 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 5a9b1d916124..f67017dcb25e 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)
219 list_del(&conn->proc_link); 219 list_del(&conn->proc_link);
220 write_unlock(&rxnet->conn_lock); 220 write_unlock(&rxnet->conn_lock);
221 kfree(conn); 221 kfree(conn);
222 if (atomic_dec_and_test(&rxnet->nr_conns))
223 wake_up_atomic_t(&rxnet->nr_conns);
222 tail = (tail + 1) & (size - 1); 224 tail = (tail + 1) & (size - 1);
223 } 225 }
224 226
diff --git a/net/rxrpc/conn_client.c b/net/rxrpc/conn_client.c
index 041da40dbf93..5736f643c516 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)
207 if (ret < 0) 207 if (ret < 0)
208 goto error_2; 208 goto error_2;
209 209
210 atomic_inc(&rxnet->nr_conns);
210 write_lock(&rxnet->conn_lock); 211 write_lock(&rxnet->conn_lock);
211 list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); 212 list_add_tail(&conn->proc_link, &rxnet->conn_proc_list);
212 write_unlock(&rxnet->conn_lock); 213 write_unlock(&rxnet->conn_lock);
diff --git a/net/rxrpc/conn_object.c b/net/rxrpc/conn_object.c
index bfc46fd69a62..0950ee3d26f5 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)
365 key_put(conn->params.key); 365 key_put(conn->params.key);
366 key_put(conn->server_key); 366 key_put(conn->server_key);
367 rxrpc_put_peer(conn->params.peer); 367 rxrpc_put_peer(conn->params.peer);
368
369 if (atomic_dec_and_test(&conn->params.local->rxnet->nr_conns))
370 wake_up_atomic_t(&conn->params.local->rxnet->nr_conns);
368 rxrpc_put_local(conn->params.local); 371 rxrpc_put_local(conn->params.local);
369 372
370 kfree(conn); 373 kfree(conn);
@@ -458,6 +461,7 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
458 461
459 _enter(""); 462 _enter("");
460 463
464 atomic_dec(&rxnet->nr_conns);
461 rxrpc_destroy_all_client_connections(rxnet); 465 rxrpc_destroy_all_client_connections(rxnet);
462 466
463 del_timer_sync(&rxnet->service_conn_reap_timer); 467 del_timer_sync(&rxnet->service_conn_reap_timer);
@@ -475,5 +479,9 @@ void rxrpc_destroy_all_connections(struct rxrpc_net *rxnet)
475 479
476 ASSERT(list_empty(&rxnet->conn_proc_list)); 480 ASSERT(list_empty(&rxnet->conn_proc_list));
477 481
482 /* We need to wait for the connections to be destroyed by RCU as they
483 * pin things that we still need to get rid of.
484 */
485 wait_on_atomic_t(&rxnet->nr_conns, atomic_t_wait, TASK_UNINTERRUPTIBLE);
478 _leave(""); 486 _leave("");
479} 487}
diff --git a/net/rxrpc/conn_service.c b/net/rxrpc/conn_service.c
index f6fcdb3130a1..80773a50c755 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
132 conn->state = RXRPC_CONN_SERVICE_PREALLOC; 132 conn->state = RXRPC_CONN_SERVICE_PREALLOC;
133 atomic_set(&conn->usage, 2); 133 atomic_set(&conn->usage, 2);
134 134
135 atomic_inc(&rxnet->nr_conns);
135 write_lock(&rxnet->conn_lock); 136 write_lock(&rxnet->conn_lock);
136 list_add_tail(&conn->link, &rxnet->service_conns); 137 list_add_tail(&conn->link, &rxnet->service_conns);
137 list_add_tail(&conn->proc_link, &rxnet->conn_proc_list); 138 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 101019b0be34..fa9ce60e7bfa 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)
57 rwlock_init(&rxnet->call_lock); 57 rwlock_init(&rxnet->call_lock);
58 atomic_set(&rxnet->nr_calls, 1); 58 atomic_set(&rxnet->nr_calls, 1);
59 59
60 atomic_set(&rxnet->nr_conns, 1);
60 INIT_LIST_HEAD(&rxnet->conn_proc_list); 61 INIT_LIST_HEAD(&rxnet->conn_proc_list);
61 INIT_LIST_HEAD(&rxnet->service_conns); 62 INIT_LIST_HEAD(&rxnet->service_conns);
62 rwlock_init(&rxnet->conn_lock); 63 rwlock_init(&rxnet->conn_lock);