diff --git a/net/tipc/core.c b/net/tipc/core.c index 49bb9fc0aa068c830366ae9aa2020a8c170eb003..7b61e1650cb028ff9504f39aaf206e64c77dbdd9 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -92,10 +92,15 @@ static int __net_init tipc_init_net(struct net *net) static void __net_exit tipc_exit_net(struct net *net) { + struct tipc_net *tn = tipc_net(net); + tipc_net_stop(net); tipc_bcast_stop(net); tipc_nametbl_stop(net); tipc_sk_rht_destroy(net); + + while (atomic_read(&tn->wq_count)) + cond_resched(); } static struct pernet_operations tipc_net_ops = { diff --git a/net/tipc/core.h b/net/tipc/core.h index 8020a6c360ffd2eeef2430308f2ba3b13b5d13cc..3abbdbffd46026eebc74ae81c5626daf499d980d 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -122,6 +122,9 @@ struct tipc_net { /* Topology subscription server */ struct tipc_topsrv *topsrv; atomic_t subscription_count; + + /* The numbers of work queues in schedule */ + atomic_t wq_count; }; static inline struct tipc_net *tipc_net(struct net *net) diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 1d623547970617136ed6429c3112610dfc7be3ae..efe822d3bb28ec8f9d9eb8afab06fe921b73db54 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -771,6 +771,7 @@ static void cleanup_bearer(struct work_struct *work) kfree_rcu(rcast, rcu); } + atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); if (ub->ubsock) udp_tunnel_sock_release(ub->ubsock); synchronize_net(); @@ -792,6 +793,7 @@ static void tipc_udp_disable(struct tipc_bearer *b) RCU_INIT_POINTER(ub->bearer, NULL); /* sock_release need to be done outside of rtnl lock */ + atomic_inc(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); INIT_WORK(&ub->work, cleanup_bearer); schedule_work(&ub->work); }