aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2015-07-16 16:54:21 -0400
committerDavid S. Miller <davem@davemloft.net>2015-07-20 23:41:14 -0400
commitd39bbd445dc44259c77bbbc8aadcce7dcdba39cc (patch)
treec82e8d60ae0426c7e0605374e285bf606fdd4ed8
parentd3a43b907ae688af6cb753c53cd7de05f3c1ba85 (diff)
tipc: move link input queue to tipc_node
At present, the link input queue and the name distributor receive queues are fields aggregated in struct tipc_link. This is a hazard, because a link might be deleted while a receiving socket still keeps reference to one of the queues. This commit fixes this bug. However, rather than adding yet another reference counter to the critical data path, we move the two queues to safe ground inside struct tipc_node, which is already protected, and let the link code only handle references to the queues. This is also in line with planned later changes in this area. Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/tipc/link.c27
-rw-r--r--net/tipc/link.h12
-rw-r--r--net/tipc/node.c4
-rw-r--r--net/tipc/node.h3
4 files changed, 27 insertions, 19 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index 03372a7e98df..f8e0e2ceceb4 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -227,7 +227,9 @@ static void link_set_timer(struct tipc_link *link, unsigned long time)
227 */ 227 */
228struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, 228struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
229 struct tipc_bearer *b_ptr, 229 struct tipc_bearer *b_ptr,
230 const struct tipc_media_addr *media_addr) 230 const struct tipc_media_addr *media_addr,
231 struct sk_buff_head *inputq,
232 struct sk_buff_head *namedq)
231{ 233{
232 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id); 234 struct tipc_net *tn = net_generic(n_ptr->net, tipc_net_id);
233 struct tipc_link *l_ptr; 235 struct tipc_link *l_ptr;
@@ -289,8 +291,9 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
289 __skb_queue_head_init(&l_ptr->backlogq); 291 __skb_queue_head_init(&l_ptr->backlogq);
290 __skb_queue_head_init(&l_ptr->deferdq); 292 __skb_queue_head_init(&l_ptr->deferdq);
291 skb_queue_head_init(&l_ptr->wakeupq); 293 skb_queue_head_init(&l_ptr->wakeupq);
292 skb_queue_head_init(&l_ptr->inputq); 294 l_ptr->inputq = inputq;
293 skb_queue_head_init(&l_ptr->namedq); 295 l_ptr->namedq = namedq;
296 skb_queue_head_init(l_ptr->inputq);
294 link_reset_statistics(l_ptr); 297 link_reset_statistics(l_ptr);
295 tipc_node_attach_link(n_ptr, l_ptr); 298 tipc_node_attach_link(n_ptr, l_ptr);
296 setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr); 299 setup_timer(&l_ptr->timer, link_timeout, (unsigned long)l_ptr);
@@ -391,8 +394,8 @@ void link_prepare_wakeup(struct tipc_link *l)
391 if ((pnd[imp] + l->backlog[imp].len) >= lim) 394 if ((pnd[imp] + l->backlog[imp].len) >= lim)
392 break; 395 break;
393 skb_unlink(skb, &l->wakeupq); 396 skb_unlink(skb, &l->wakeupq);
394 skb_queue_tail(&l->inputq, skb); 397 skb_queue_tail(l->inputq, skb);
395 l->owner->inputq = &l->inputq; 398 l->owner->inputq = l->inputq;
396 l->owner->action_flags |= TIPC_MSG_EVT; 399 l->owner->action_flags |= TIPC_MSG_EVT;
397 } 400 }
398} 401}
@@ -465,7 +468,7 @@ void tipc_link_reset(struct tipc_link *l_ptr)
465 __skb_queue_purge(&l_ptr->transmq); 468 __skb_queue_purge(&l_ptr->transmq);
466 __skb_queue_purge(&l_ptr->deferdq); 469 __skb_queue_purge(&l_ptr->deferdq);
467 if (!owner->inputq) 470 if (!owner->inputq)
468 owner->inputq = &l_ptr->inputq; 471 owner->inputq = l_ptr->inputq;
469 skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq); 472 skb_queue_splice_init(&l_ptr->wakeupq, owner->inputq);
470 if (!skb_queue_empty(owner->inputq)) 473 if (!skb_queue_empty(owner->inputq))
471 owner->action_flags |= TIPC_MSG_EVT; 474 owner->action_flags |= TIPC_MSG_EVT;
@@ -962,7 +965,7 @@ static bool link_synch(struct tipc_link *l)
962 965
963 /* Is it still in the input queue ? */ 966 /* Is it still in the input queue ? */
964 post_synch = mod(pl->rcv_nxt - l->synch_point) - 1; 967 post_synch = mod(pl->rcv_nxt - l->synch_point) - 1;
965 if (skb_queue_len(&pl->inputq) > post_synch) 968 if (skb_queue_len(pl->inputq) > post_synch)
966 return false; 969 return false;
967synched: 970synched:
968 l->flags &= ~LINK_SYNCHING; 971 l->flags &= ~LINK_SYNCHING;
@@ -1141,16 +1144,16 @@ static bool tipc_data_input(struct tipc_link *link, struct sk_buff *skb)
1141 case TIPC_HIGH_IMPORTANCE: 1144 case TIPC_HIGH_IMPORTANCE:
1142 case TIPC_CRITICAL_IMPORTANCE: 1145 case TIPC_CRITICAL_IMPORTANCE:
1143 case CONN_MANAGER: 1146 case CONN_MANAGER:
1144 if (tipc_skb_queue_tail(&link->inputq, skb, dport)) { 1147 if (tipc_skb_queue_tail(link->inputq, skb, dport)) {
1145 node->inputq = &link->inputq; 1148 node->inputq = link->inputq;
1146 node->action_flags |= TIPC_MSG_EVT; 1149 node->action_flags |= TIPC_MSG_EVT;
1147 } 1150 }
1148 return true; 1151 return true;
1149 case NAME_DISTRIBUTOR: 1152 case NAME_DISTRIBUTOR:
1150 node->bclink.recv_permitted = true; 1153 node->bclink.recv_permitted = true;
1151 node->namedq = &link->namedq; 1154 node->namedq = link->namedq;
1152 skb_queue_tail(&link->namedq, skb); 1155 skb_queue_tail(link->namedq, skb);
1153 if (skb_queue_len(&link->namedq) == 1) 1156 if (skb_queue_len(link->namedq) == 1)
1154 node->action_flags |= TIPC_NAMED_MSG_EVT; 1157 node->action_flags |= TIPC_NAMED_MSG_EVT;
1155 return true; 1158 return true;
1156 case MSG_BUNDLER: 1159 case MSG_BUNDLER:
diff --git a/net/tipc/link.h b/net/tipc/link.h
index ae0a0ea572f2..9c71d9e42e93 100644
--- a/net/tipc/link.h
+++ b/net/tipc/link.h
@@ -192,8 +192,8 @@ struct tipc_link {
192 u16 rcv_nxt; 192 u16 rcv_nxt;
193 u32 rcv_unacked; 193 u32 rcv_unacked;
194 struct sk_buff_head deferdq; 194 struct sk_buff_head deferdq;
195 struct sk_buff_head inputq; 195 struct sk_buff_head *inputq;
196 struct sk_buff_head namedq; 196 struct sk_buff_head *namedq;
197 197
198 /* Congestion handling */ 198 /* Congestion handling */
199 struct sk_buff_head wakeupq; 199 struct sk_buff_head wakeupq;
@@ -207,9 +207,11 @@ struct tipc_link {
207 207
208struct tipc_port; 208struct tipc_port;
209 209
210struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, 210struct tipc_link *tipc_link_create(struct tipc_node *n,
211 struct tipc_bearer *b_ptr, 211 struct tipc_bearer *b,
212 const struct tipc_media_addr *media_addr); 212 const struct tipc_media_addr *maddr,
213 struct sk_buff_head *inputq,
214 struct sk_buff_head *namedq);
213void tipc_link_delete(struct tipc_link *link); 215void tipc_link_delete(struct tipc_link *link);
214void tipc_link_delete_list(struct net *net, unsigned int bearer_id); 216void tipc_link_delete_list(struct net *net, unsigned int bearer_id);
215void tipc_link_failover_send_queue(struct tipc_link *l_ptr); 217void tipc_link_failover_send_queue(struct tipc_link *l_ptr);
diff --git a/net/tipc/node.c b/net/tipc/node.c
index 06f642abdf38..20ec61ceffac 100644
--- a/net/tipc/node.c
+++ b/net/tipc/node.c
@@ -132,6 +132,7 @@ struct tipc_node *tipc_node_create(struct net *net, u32 addr)
132 INIT_LIST_HEAD(&n_ptr->list); 132 INIT_LIST_HEAD(&n_ptr->list);
133 INIT_LIST_HEAD(&n_ptr->publ_list); 133 INIT_LIST_HEAD(&n_ptr->publ_list);
134 INIT_LIST_HEAD(&n_ptr->conn_sks); 134 INIT_LIST_HEAD(&n_ptr->conn_sks);
135 skb_queue_head_init(&n_ptr->bclink.namedq);
135 __skb_queue_head_init(&n_ptr->bclink.deferdq); 136 __skb_queue_head_init(&n_ptr->bclink.deferdq);
136 hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]); 137 hlist_add_head_rcu(&n_ptr->hash, &tn->node_htable[tipc_hashfn(addr)]);
137 list_for_each_entry_rcu(temp_node, &tn->node_list, list) { 138 list_for_each_entry_rcu(temp_node, &tn->node_list, list) {
@@ -350,9 +351,10 @@ bool tipc_node_update_dest(struct tipc_node *n, struct tipc_bearer *b,
350{ 351{
351 struct tipc_link *l = n->links[b->identity].link; 352 struct tipc_link *l = n->links[b->identity].link;
352 struct tipc_media_addr *curr = &n->links[b->identity].maddr; 353 struct tipc_media_addr *curr = &n->links[b->identity].maddr;
354 struct sk_buff_head *inputq = &n->links[b->identity].inputq;
353 355
354 if (!l) 356 if (!l)
355 l = tipc_link_create(n, b, maddr); 357 l = tipc_link_create(n, b, maddr, inputq, &n->bclink.namedq);
356 if (!l) 358 if (!l)
357 return false; 359 return false;
358 memcpy(&l->media_addr, maddr, sizeof(*maddr)); 360 memcpy(&l->media_addr, maddr, sizeof(*maddr));
diff --git a/net/tipc/node.h b/net/tipc/node.h
index 68579c70748b..0657cbf1f5cd 100644
--- a/net/tipc/node.h
+++ b/net/tipc/node.h
@@ -85,13 +85,14 @@ struct tipc_node_bclink {
85 u32 deferred_size; 85 u32 deferred_size;
86 struct sk_buff_head deferdq; 86 struct sk_buff_head deferdq;
87 struct sk_buff *reasm_buf; 87 struct sk_buff *reasm_buf;
88 int inputq_map; 88 struct sk_buff_head namedq;
89 bool recv_permitted; 89 bool recv_permitted;
90}; 90};
91 91
92struct tipc_link_entry { 92struct tipc_link_entry {
93 struct tipc_link *link; 93 struct tipc_link *link;
94 u32 mtu; 94 u32 mtu;
95 struct sk_buff_head inputq;
95 struct tipc_media_addr maddr; 96 struct tipc_media_addr maddr;
96}; 97};
97 98