Skip to content

Commit

Permalink
tipc: Fix node lock problems during broadcast message reception
Browse files Browse the repository at this point in the history
Modifies TIPC's incoming broadcast packet handler to ensure that the
node lock associated with the sender of the packet is held whenever
node-related data structure fields are accessed. The routine is also
restructured with a single exit point, making it easier to ensure
the node lock is properly released and the incoming packet is properly
disposed of.

Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
  • Loading branch information
Allan Stephens authored and Paul Gortmaker committed Sep 1, 2011
1 parent 169073d commit 5d3c488
Showing 1 changed file with 23 additions and 13 deletions.
36 changes: 23 additions & 13 deletions net/tipc/bcast.c
Original file line number Diff line number Diff line change
Expand Up @@ -426,20 +426,26 @@ int tipc_bclink_send_msg(struct sk_buff *buf)
void tipc_bclink_recv_pkt(struct sk_buff *buf)
{
struct tipc_msg *msg = buf_msg(buf);
struct tipc_node *node = tipc_node_find(msg_prevnode(msg));
struct tipc_node *node;
u32 next_in;
u32 seqno;
struct sk_buff *deferred;

if (unlikely(!node || !tipc_node_is_up(node) || !node->bclink.supported ||
(msg_mc_netid(msg) != tipc_net_id))) {
buf_discard(buf);
return;
}
/* Screen out unwanted broadcast messages */

if (msg_mc_netid(msg) != tipc_net_id)
goto exit;

node = tipc_node_find(msg_prevnode(msg));
if (unlikely(!node))
goto exit;

tipc_node_lock(node);
if (unlikely(!node->bclink.supported))
goto unlock;

if (unlikely(msg_user(msg) == BCAST_PROTOCOL)) {
if (msg_destnode(msg) == tipc_own_addr) {
tipc_node_lock(node);
tipc_bclink_acknowledge(node, msg_bcast_ack(msg));
tipc_node_unlock(node);
spin_lock_bh(&bc_lock);
Expand All @@ -449,16 +455,17 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
msg_bcgap_to(msg));
spin_unlock_bh(&bc_lock);
} else {
tipc_node_unlock(node);
tipc_bclink_peek_nack(msg_destnode(msg),
msg_bcast_tag(msg),
msg_bcgap_after(msg),
msg_bcgap_to(msg));
}
buf_discard(buf);
return;
goto exit;
}

tipc_node_lock(node);
/* Handle in-sequence broadcast message */

receive:
deferred = node->bclink.deferred_head;
next_in = mod(node->bclink.last_in + 1);
Expand Down Expand Up @@ -491,14 +498,14 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
tipc_node_unlock(node);
tipc_net_route_msg(buf);
}
buf = NULL;
tipc_node_lock(node);
if (deferred && (buf_seqno(deferred) == mod(next_in + 1))) {
tipc_node_lock(node);
buf = deferred;
msg = buf_msg(buf);
node->bclink.deferred_head = deferred->next;
goto receive;
}
return;
} else if (less(next_in, seqno)) {
u32 gap_after = node->bclink.gap_after;
u32 gap_to = node->bclink.gap_to;
Expand All @@ -513,16 +520,19 @@ void tipc_bclink_recv_pkt(struct sk_buff *buf)
else if (less(gap_after, seqno) && less(seqno, gap_to))
node->bclink.gap_to = seqno;
}
buf = NULL;
if (bclink_ack_allowed(node->bclink.nack_sync)) {
if (gap_to != gap_after)
bclink_send_nack(node);
bclink_set_gap(node);
}
} else {
bcl->stats.duplicates++;
buf_discard(buf);
}
unlock:
tipc_node_unlock(node);
exit:
buf_discard(buf);
}

u32 tipc_bclink_acks_missing(struct tipc_node *n_ptr)
Expand Down

0 comments on commit 5d3c488

Please sign in to comment.