rxrpc: Allow list of in-use local UDP endpoints to be viewed in /proc
[ Upstream commit 33912c2639ad76660988c8ca97e4d18fca89b668 ] Allow the list of in-use local UDP endpoints in the current network namespace to be viewed in /proc. To aid with this, the endpoint list is converted to an hlist and RCU-safe manipulation is used so that the list can be read with only the RCU read lock held. Signed-off-by: David Howells <dhowells@redhat.com> cc: Marc Dionne <marc.dionne@auristor.com> cc: linux-afs@lists.infradead.org Signed-off-by: David S. Miller <davem@davemloft.net> Stable-dep-of: 3bcd6c7eaa53 ("rxrpc: Fix race between conn bundle lookup and bundle removal [ZDI-CAN-15975]") Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:

committed by
Greg Kroah-Hartman

parent
a2d5dba2fc
commit
bddde342c6
@@ -81,7 +81,7 @@ static struct rxrpc_local *rxrpc_alloc_local(struct rxrpc_net *rxnet,
|
||||
atomic_set(&local->usage, 1);
|
||||
atomic_set(&local->active_users, 1);
|
||||
local->rxnet = rxnet;
|
||||
INIT_LIST_HEAD(&local->link);
|
||||
INIT_HLIST_NODE(&local->link);
|
||||
INIT_WORK(&local->processor, rxrpc_local_processor);
|
||||
init_rwsem(&local->defrag_sem);
|
||||
skb_queue_head_init(&local->reject_queue);
|
||||
@@ -199,7 +199,7 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
|
||||
{
|
||||
struct rxrpc_local *local;
|
||||
struct rxrpc_net *rxnet = rxrpc_net(net);
|
||||
struct list_head *cursor;
|
||||
struct hlist_node *cursor;
|
||||
const char *age;
|
||||
long diff;
|
||||
int ret;
|
||||
@@ -209,16 +209,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
|
||||
|
||||
mutex_lock(&rxnet->local_mutex);
|
||||
|
||||
for (cursor = rxnet->local_endpoints.next;
|
||||
cursor != &rxnet->local_endpoints;
|
||||
cursor = cursor->next) {
|
||||
local = list_entry(cursor, struct rxrpc_local, link);
|
||||
hlist_for_each(cursor, &rxnet->local_endpoints) {
|
||||
local = hlist_entry(cursor, struct rxrpc_local, link);
|
||||
|
||||
diff = rxrpc_local_cmp_key(local, srx);
|
||||
if (diff < 0)
|
||||
if (diff != 0)
|
||||
continue;
|
||||
if (diff > 0)
|
||||
break;
|
||||
|
||||
/* Services aren't allowed to share transport sockets, so
|
||||
* reject that here. It is possible that the object is dying -
|
||||
@@ -230,9 +226,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
|
||||
goto addr_in_use;
|
||||
}
|
||||
|
||||
/* Found a match. We replace a dying object. Attempting to
|
||||
* bind the transport socket may still fail if we're attempting
|
||||
* to use a local address that the dying object is still using.
|
||||
/* Found a match. We want to replace a dying object.
|
||||
* Attempting to bind the transport socket may still fail if
|
||||
* we're attempting to use a local address that the dying
|
||||
* object is still using.
|
||||
*/
|
||||
if (!rxrpc_use_local(local))
|
||||
break;
|
||||
@@ -249,10 +246,12 @@ struct rxrpc_local *rxrpc_lookup_local(struct net *net,
|
||||
if (ret < 0)
|
||||
goto sock_error;
|
||||
|
||||
if (cursor != &rxnet->local_endpoints)
|
||||
list_replace_init(cursor, &local->link);
|
||||
else
|
||||
list_add_tail(&local->link, cursor);
|
||||
if (cursor) {
|
||||
hlist_replace_rcu(cursor, &local->link);
|
||||
cursor->pprev = NULL;
|
||||
} else {
|
||||
hlist_add_head_rcu(&local->link, &rxnet->local_endpoints);
|
||||
}
|
||||
age = "new";
|
||||
|
||||
found:
|
||||
@@ -393,7 +392,7 @@ static void rxrpc_local_destroyer(struct rxrpc_local *local)
|
||||
local->dead = true;
|
||||
|
||||
mutex_lock(&rxnet->local_mutex);
|
||||
list_del_init(&local->link);
|
||||
hlist_del_init_rcu(&local->link);
|
||||
mutex_unlock(&rxnet->local_mutex);
|
||||
|
||||
rxrpc_clean_up_local_conns(local);
|
||||
@@ -480,9 +479,9 @@ void rxrpc_destroy_all_locals(struct rxrpc_net *rxnet)
|
||||
|
||||
flush_workqueue(rxrpc_workqueue);
|
||||
|
||||
if (!list_empty(&rxnet->local_endpoints)) {
|
||||
if (!hlist_empty(&rxnet->local_endpoints)) {
|
||||
mutex_lock(&rxnet->local_mutex);
|
||||
list_for_each_entry(local, &rxnet->local_endpoints, link) {
|
||||
hlist_for_each_entry(local, &rxnet->local_endpoints, link) {
|
||||
pr_err("AF_RXRPC: Leaked local %p {%d}\n",
|
||||
local, atomic_read(&local->usage));
|
||||
}
|
||||
|
Reference in New Issue
Block a user