--- x/net/rxrpc/ar-internal.h +++ y/net/rxrpc/ar-internal.h @@ -299,6 +299,7 @@ struct rxrpc_local { bool dead; bool service_closed; /* Service socket closed */ struct sockaddr_rxrpc srx; /* local address */ + struct work_struct destroy_work; }; /* --- x/net/rxrpc/local_object.c +++ y/net/rxrpc/local_object.c @@ -312,6 +312,20 @@ struct rxrpc_local *rxrpc_get_local_mayb return NULL; } +static void rxrpc_local_destroy_workfn(struct work_struct *w) +{ + struct rxrpc_local *local = container_of(w, struct rxrpc_local, destroy_work); + struct rxrpc_net *rxnet = local->rxnet; + + mutex_lock(&rxnet->local_mutex); + if (!hlist_unhashed(&local->link)) + hlist_del_init_rcu(&local->link); + mutex_unlock(&rxnet->local_mutex); + + rxrpc_see_local(local, rxrpc_local_free); + kfree(local); +} + /* * Drop a ref on a local endpoint. */ @@ -328,8 +342,10 @@ void rxrpc_put_local(struct rxrpc_local dead = __refcount_dec_and_test(&local->ref, &r); trace_rxrpc_local(debug_id, why, r, u); - if (dead) - call_rcu(&local->rcu, rxrpc_local_rcu); + if (!dead) + return; + INIT_WORK(&local->destroy_work, rxrpc_local_destroy_workfn); + schedule_work(&local->destroy_work); } }