--- 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); } } --- x/kernel/rcu/tree_plugin.h +++ y/kernel/rcu/tree_plugin.h @@ -156,6 +156,8 @@ static void rcu_preempt_ctxt_queue(struc (rnp->qsmask & rdp->grpmask ? RCU_GP_BLKD : 0) + (rnp->expmask & rdp->grpmask ? RCU_EXP_BLKD : 0); struct task_struct *t = current; + int w = 0; + static int __loop = 0; raw_lockdep_assert_held_rcu_node(rnp); WARN_ON_ONCE(rdp->mynode != rnp); @@ -183,6 +185,7 @@ static void rcu_preempt_ctxt_queue(struc * blocking the already-waiting GPs. */ list_add(&t->rcu_node_entry, &rnp->blkd_tasks); + w = 1; break; case RCU_EXP_BLKD: @@ -201,6 +204,7 @@ static void rcu_preempt_ctxt_queue(struc * already queued tasks that are not blocking it. */ list_add_tail(&t->rcu_node_entry, &rnp->blkd_tasks); + w = 1; break; case RCU_EXP_TASKS + RCU_EXP_BLKD: @@ -262,6 +266,7 @@ static void rcu_preempt_ctxt_queue(struc rcu_report_exp_rdp(rdp); else WARN_ON_ONCE(rdp->cpu_no_qs.b.exp); + WARN_ON_ONCE(w && __loop++ > 100); } /*