diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/core.c | 2 | ||||
-rw-r--r-- | net/tipc/core.h | 2 | ||||
-rw-r--r-- | net/tipc/msg.c | 9 | ||||
-rw-r--r-- | net/tipc/socket.c | 5 | ||||
-rw-r--r-- | net/tipc/udp_media.c | 2 |
5 files changed, 12 insertions, 8 deletions
diff --git a/net/tipc/core.c b/net/tipc/core.c index c2ff42900b53..40c03085c0ea 100644 --- a/net/tipc/core.c +++ b/net/tipc/core.c @@ -121,6 +121,8 @@ static void __net_exit tipc_exit_net(struct net *net) #ifdef CONFIG_TIPC_CRYPTO tipc_crypto_stop(&tipc_net(net)->crypto_tx); #endif + while (atomic_read(&tn->wq_count)) + cond_resched(); } static void __net_exit tipc_pernet_pre_exit(struct net *net) diff --git a/net/tipc/core.h b/net/tipc/core.h index 1d57a4d3b05e..992924a849be 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h @@ -151,6 +151,8 @@ struct tipc_net { #endif /* 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/msg.c b/net/tipc/msg.c index 32c79c59052b..88a3ed80094c 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c @@ -151,18 +151,13 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf) if (unlikely(head)) goto err; *buf = NULL; + if (skb_has_frag_list(frag) && __skb_linearize(frag)) + goto err; frag = skb_unshare(frag, GFP_ATOMIC); if (unlikely(!frag)) goto err; head = *headbuf = frag; TIPC_SKB_CB(head)->tail = NULL; - if (skb_is_nonlinear(head)) { - skb_walk_frags(head, tail) { - TIPC_SKB_CB(head)->tail = tail; - } - } else { - skb_frag_list_init(head); - } return 0; } diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 5b18c6a46cfb..9f7cc9e1e4ef 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c @@ -1244,7 +1244,10 @@ void tipc_sk_mcast_rcv(struct net *net, struct sk_buff_head *arrvq, spin_lock_bh(&inputq->lock); if (skb_peek(arrvq) == skb) { skb_queue_splice_tail_init(&tmpq, inputq); - __skb_dequeue(arrvq); + /* Decrease the skb's refcnt as increasing in the + * function tipc_skb_peek + */ + kfree_skb(__skb_dequeue(arrvq)); } spin_unlock_bh(&inputq->lock); __skb_queue_purge(&tmpq); diff --git a/net/tipc/udp_media.c b/net/tipc/udp_media.c index 1d17f4470ee2..a23628108272 100644 --- a/net/tipc/udp_media.c +++ b/net/tipc/udp_media.c @@ -806,6 +806,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(); @@ -826,6 +827,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); } |