diff --git a/net/tipc/core.c b/net/tipc/core.c index e3d79f8b69d8..90cf7e0bbaf0 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -107,6 +107,9 @@ static void __net_exit tipc_exit_net(struct net *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 e119c4a88d63..c6bda91f8581 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -143,6 +143,8 @@ struct tipc_net { /* Work item for net finalize */ struct tipc_net_work final_work; + /* 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 8f0977a9d423..1fb0535e2eb4 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -802,6 +802,7 @@ static void cleanup_bearer(struct work_struct *work) kfree_rcu(rcast, rcu); } + atomic_dec(&tipc_net(sock_net(ub->ubsock->sk))->wq_count); dst_cache_destroy(&ub->rcast.dst_cache); udp_tunnel_sock_release(ub->ubsock); synchronize_net(); @@ -822,6 +823,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); }