tipc: refactor node xmit and fix memory leaks
Refactor tipc_node_xmit() to fail fast and fail early. Fix several potential memory leaks in unexpected error paths. Reported-by: Dmitry Vyukov <dvyukov@google.com> Reviewed-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: Richard Alpe <richard.alpe@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
37ace20a3c
commit
4952cd3e7b
|
@ -903,8 +903,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
|
||||||
if (unlikely(l->backlog[i].len >= l->backlog[i].limit))
|
if (unlikely(l->backlog[i].len >= l->backlog[i].limit))
|
||||||
return link_schedule_user(l, list);
|
return link_schedule_user(l, list);
|
||||||
}
|
}
|
||||||
if (unlikely(msg_size(hdr) > mtu))
|
if (unlikely(msg_size(hdr) > mtu)) {
|
||||||
|
skb_queue_purge(list);
|
||||||
return -EMSGSIZE;
|
return -EMSGSIZE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Prepare each packet for sending, and add to relevant queue: */
|
/* Prepare each packet for sending, and add to relevant queue: */
|
||||||
while (skb_queue_len(list)) {
|
while (skb_queue_len(list)) {
|
||||||
|
@ -916,8 +918,10 @@ int tipc_link_xmit(struct tipc_link *l, struct sk_buff_head *list,
|
||||||
|
|
||||||
if (likely(skb_queue_len(transmq) < maxwin)) {
|
if (likely(skb_queue_len(transmq) < maxwin)) {
|
||||||
_skb = skb_clone(skb, GFP_ATOMIC);
|
_skb = skb_clone(skb, GFP_ATOMIC);
|
||||||
if (!_skb)
|
if (!_skb) {
|
||||||
|
skb_queue_purge(list);
|
||||||
return -ENOBUFS;
|
return -ENOBUFS;
|
||||||
|
}
|
||||||
__skb_dequeue(list);
|
__skb_dequeue(list);
|
||||||
__skb_queue_tail(transmq, skb);
|
__skb_queue_tail(transmq, skb);
|
||||||
__skb_queue_tail(xmitq, _skb);
|
__skb_queue_tail(xmitq, _skb);
|
||||||
|
|
|
@ -1166,7 +1166,7 @@ msg_full:
|
||||||
* @dnode: address of destination node
|
* @dnode: address of destination node
|
||||||
* @selector: a number used for deterministic link selection
|
* @selector: a number used for deterministic link selection
|
||||||
* Consumes the buffer chain, except when returning -ELINKCONG
|
* Consumes the buffer chain, except when returning -ELINKCONG
|
||||||
* Returns 0 if success, otherwise errno: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE
|
* Returns 0 if success, otherwise: -ELINKCONG,-EHOSTUNREACH,-EMSGSIZE,-ENOBUF
|
||||||
*/
|
*/
|
||||||
int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
|
int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
|
||||||
u32 dnode, int selector)
|
u32 dnode, int selector)
|
||||||
|
@ -1174,33 +1174,43 @@ int tipc_node_xmit(struct net *net, struct sk_buff_head *list,
|
||||||
struct tipc_link_entry *le = NULL;
|
struct tipc_link_entry *le = NULL;
|
||||||
struct tipc_node *n;
|
struct tipc_node *n;
|
||||||
struct sk_buff_head xmitq;
|
struct sk_buff_head xmitq;
|
||||||
int bearer_id = -1;
|
int bearer_id;
|
||||||
int rc = -EHOSTUNREACH;
|
int rc;
|
||||||
|
|
||||||
__skb_queue_head_init(&xmitq);
|
if (in_own_node(net, dnode)) {
|
||||||
n = tipc_node_find(net, dnode);
|
|
||||||
if (likely(n)) {
|
|
||||||
tipc_node_read_lock(n);
|
|
||||||
bearer_id = n->active_links[selector & 1];
|
|
||||||
if (bearer_id >= 0) {
|
|
||||||
le = &n->links[bearer_id];
|
|
||||||
spin_lock_bh(&le->lock);
|
|
||||||
rc = tipc_link_xmit(le->link, list, &xmitq);
|
|
||||||
spin_unlock_bh(&le->lock);
|
|
||||||
}
|
|
||||||
tipc_node_read_unlock(n);
|
|
||||||
if (likely(!rc))
|
|
||||||
tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
|
|
||||||
else if (rc == -ENOBUFS)
|
|
||||||
tipc_node_link_down(n, bearer_id, false);
|
|
||||||
tipc_node_put(n);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (likely(in_own_node(net, dnode))) {
|
|
||||||
tipc_sk_rcv(net, list);
|
tipc_sk_rcv(net, list);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
n = tipc_node_find(net, dnode);
|
||||||
|
if (unlikely(!n)) {
|
||||||
|
skb_queue_purge(list);
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
}
|
||||||
|
|
||||||
|
tipc_node_read_lock(n);
|
||||||
|
bearer_id = n->active_links[selector & 1];
|
||||||
|
if (unlikely(bearer_id == INVALID_BEARER_ID)) {
|
||||||
|
tipc_node_read_unlock(n);
|
||||||
|
tipc_node_put(n);
|
||||||
|
skb_queue_purge(list);
|
||||||
|
return -EHOSTUNREACH;
|
||||||
|
}
|
||||||
|
|
||||||
|
__skb_queue_head_init(&xmitq);
|
||||||
|
le = &n->links[bearer_id];
|
||||||
|
spin_lock_bh(&le->lock);
|
||||||
|
rc = tipc_link_xmit(le->link, list, &xmitq);
|
||||||
|
spin_unlock_bh(&le->lock);
|
||||||
|
tipc_node_read_unlock(n);
|
||||||
|
|
||||||
|
if (likely(rc == 0))
|
||||||
|
tipc_bearer_xmit(net, bearer_id, &xmitq, &le->maddr);
|
||||||
|
else if (rc == -ENOBUFS)
|
||||||
|
tipc_node_link_down(n, bearer_id, false);
|
||||||
|
|
||||||
|
tipc_node_put(n);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue