diff options
Diffstat (limited to 'net/tipc/link.c')
-rw-r--r-- | net/tipc/link.c | 127 |
1 files changed, 60 insertions, 67 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c index fb1485dc6736..1db162aa64a5 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -36,7 +36,6 @@ | |||
36 | 36 | ||
37 | #include "core.h" | 37 | #include "core.h" |
38 | #include "link.h" | 38 | #include "link.h" |
39 | #include "port.h" | ||
40 | #include "socket.h" | 39 | #include "socket.h" |
41 | #include "name_distr.h" | 40 | #include "name_distr.h" |
42 | #include "discover.h" | 41 | #include "discover.h" |
@@ -275,7 +274,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
275 | link_init_max_pkt(l_ptr); | 274 | link_init_max_pkt(l_ptr); |
276 | 275 | ||
277 | l_ptr->next_out_no = 1; | 276 | l_ptr->next_out_no = 1; |
278 | INIT_LIST_HEAD(&l_ptr->waiting_ports); | 277 | __skb_queue_head_init(&l_ptr->waiting_sks); |
279 | 278 | ||
280 | link_reset_statistics(l_ptr); | 279 | link_reset_statistics(l_ptr); |
281 | 280 | ||
@@ -322,66 +321,47 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) | |||
322 | } | 321 | } |
323 | 322 | ||
324 | /** | 323 | /** |
325 | * link_schedule_port - schedule port for deferred sending | 324 | * link_schedule_user - schedule user for wakeup after congestion |
326 | * @l_ptr: pointer to link | 325 | * @link: congested link |
327 | * @origport: reference to sending port | 326 | * @oport: sending port |
328 | * @sz: amount of data to be sent | 327 | * @chain_sz: size of buffer chain that was attempted sent |
329 | * | 328 | * @imp: importance of message attempted sent |
330 | * Schedules port for renewed sending of messages after link congestion | 329 | * Create pseudo msg to send back to user when congestion abates |
331 | * has abated. | ||
332 | */ | 330 | */ |
333 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) | 331 | static bool link_schedule_user(struct tipc_link *link, u32 oport, |
332 | uint chain_sz, uint imp) | ||
334 | { | 333 | { |
335 | struct tipc_port *p_ptr; | 334 | struct sk_buff *buf; |
336 | struct tipc_sock *tsk; | ||
337 | 335 | ||
338 | spin_lock_bh(&tipc_port_list_lock); | 336 | buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr, |
339 | p_ptr = tipc_port_lock(origport); | 337 | tipc_own_addr, oport, 0, 0); |
340 | if (p_ptr) { | 338 | if (!buf) |
341 | if (!list_empty(&p_ptr->wait_list)) | 339 | return false; |
342 | goto exit; | 340 | TIPC_SKB_CB(buf)->chain_sz = chain_sz; |
343 | tsk = tipc_port_to_sock(p_ptr); | 341 | TIPC_SKB_CB(buf)->chain_imp = imp; |
344 | tsk->link_cong = 1; | 342 | __skb_queue_tail(&link->waiting_sks, buf); |
345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); | 343 | link->stats.link_congs++; |
346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); | 344 | return true; |
347 | l_ptr->stats.link_congs++; | ||
348 | exit: | ||
349 | tipc_port_unlock(p_ptr); | ||
350 | } | ||
351 | spin_unlock_bh(&tipc_port_list_lock); | ||
352 | return -ELINKCONG; | ||
353 | } | 345 | } |
354 | 346 | ||
355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | 347 | /** |
348 | * link_prepare_wakeup - prepare users for wakeup after congestion | ||
349 | * @link: congested link | ||
350 | * Move a number of waiting users, as permitted by available space in | ||
351 | * the send queue, from link wait queue to node wait queue for wakeup | ||
352 | */ | ||
353 | static void link_prepare_wakeup(struct tipc_link *link) | ||
356 | { | 354 | { |
357 | struct tipc_port *p_ptr; | 355 | struct sk_buff_head *wq = &link->waiting_sks; |
358 | struct tipc_sock *tsk; | 356 | struct sk_buff *buf; |
359 | struct tipc_port *temp_p_ptr; | 357 | uint pend_qsz = link->out_queue_size; |
360 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; | 358 | |
361 | 359 | for (buf = skb_peek(wq); buf; buf = skb_peek(wq)) { | |
362 | if (all) | 360 | if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(buf)->chain_imp]) |
363 | win = 100000; | ||
364 | if (win <= 0) | ||
365 | return; | ||
366 | if (!spin_trylock_bh(&tipc_port_list_lock)) | ||
367 | return; | ||
368 | if (link_congested(l_ptr)) | ||
369 | goto exit; | ||
370 | list_for_each_entry_safe(p_ptr, temp_p_ptr, &l_ptr->waiting_ports, | ||
371 | wait_list) { | ||
372 | if (win <= 0) | ||
373 | break; | 361 | break; |
374 | tsk = tipc_port_to_sock(p_ptr); | 362 | pend_qsz += TIPC_SKB_CB(buf)->chain_sz; |
375 | list_del_init(&p_ptr->wait_list); | 363 | __skb_queue_tail(&link->owner->waiting_sks, __skb_dequeue(wq)); |
376 | spin_lock_bh(p_ptr->lock); | ||
377 | tsk->link_cong = 0; | ||
378 | tipc_sock_wakeup(tsk); | ||
379 | win -= p_ptr->waiting_pkts; | ||
380 | spin_unlock_bh(p_ptr->lock); | ||
381 | } | 364 | } |
382 | |||
383 | exit: | ||
384 | spin_unlock_bh(&tipc_port_list_lock); | ||
385 | } | 365 | } |
386 | 366 | ||
387 | /** | 367 | /** |
@@ -423,6 +403,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
423 | u32 prev_state = l_ptr->state; | 403 | u32 prev_state = l_ptr->state; |
424 | u32 checkpoint = l_ptr->next_in_no; | 404 | u32 checkpoint = l_ptr->next_in_no; |
425 | int was_active_link = tipc_link_is_active(l_ptr); | 405 | int was_active_link = tipc_link_is_active(l_ptr); |
406 | struct tipc_node *owner = l_ptr->owner; | ||
426 | 407 | ||
427 | msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); | 408 | msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); |
428 | 409 | ||
@@ -450,9 +431,10 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
450 | kfree_skb(l_ptr->proto_msg_queue); | 431 | kfree_skb(l_ptr->proto_msg_queue); |
451 | l_ptr->proto_msg_queue = NULL; | 432 | l_ptr->proto_msg_queue = NULL; |
452 | kfree_skb_list(l_ptr->oldest_deferred_in); | 433 | kfree_skb_list(l_ptr->oldest_deferred_in); |
453 | if (!list_empty(&l_ptr->waiting_ports)) | 434 | if (!skb_queue_empty(&l_ptr->waiting_sks)) { |
454 | tipc_link_wakeup_ports(l_ptr, 1); | 435 | skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks); |
455 | 436 | owner->action_flags |= TIPC_WAKEUP_USERS; | |
437 | } | ||
456 | l_ptr->retransm_queue_head = 0; | 438 | l_ptr->retransm_queue_head = 0; |
457 | l_ptr->retransm_queue_size = 0; | 439 | l_ptr->retransm_queue_size = 0; |
458 | l_ptr->last_out = NULL; | 440 | l_ptr->last_out = NULL; |
@@ -688,19 +670,23 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event) | |||
688 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) | 670 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) |
689 | { | 671 | { |
690 | struct tipc_msg *msg = buf_msg(buf); | 672 | struct tipc_msg *msg = buf_msg(buf); |
691 | uint psz = msg_size(msg); | ||
692 | uint imp = tipc_msg_tot_importance(msg); | 673 | uint imp = tipc_msg_tot_importance(msg); |
693 | u32 oport = msg_tot_origport(msg); | 674 | u32 oport = msg_tot_origport(msg); |
694 | 675 | ||
695 | if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) { | 676 | if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) { |
696 | if (!msg_errcode(msg) && !msg_reroute_cnt(msg)) { | ||
697 | link_schedule_port(link, oport, psz); | ||
698 | return -ELINKCONG; | ||
699 | } | ||
700 | } else { | ||
701 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); | 677 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); |
702 | tipc_link_reset(link); | 678 | tipc_link_reset(link); |
679 | goto drop; | ||
703 | } | 680 | } |
681 | if (unlikely(msg_errcode(msg))) | ||
682 | goto drop; | ||
683 | if (unlikely(msg_reroute_cnt(msg))) | ||
684 | goto drop; | ||
685 | if (TIPC_SKB_CB(buf)->wakeup_pending) | ||
686 | return -ELINKCONG; | ||
687 | if (link_schedule_user(link, oport, TIPC_SKB_CB(buf)->chain_sz, imp)) | ||
688 | return -ELINKCONG; | ||
689 | drop: | ||
704 | kfree_skb_list(buf); | 690 | kfree_skb_list(buf); |
705 | return -EHOSTUNREACH; | 691 | return -EHOSTUNREACH; |
706 | } | 692 | } |
@@ -1202,8 +1188,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1202 | if (unlikely(l_ptr->next_out)) | 1188 | if (unlikely(l_ptr->next_out)) |
1203 | tipc_link_push_queue(l_ptr); | 1189 | tipc_link_push_queue(l_ptr); |
1204 | 1190 | ||
1205 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) | 1191 | if (released && !skb_queue_empty(&l_ptr->waiting_sks)) { |
1206 | tipc_link_wakeup_ports(l_ptr, 0); | 1192 | link_prepare_wakeup(l_ptr); |
1193 | l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS; | ||
1194 | } | ||
1207 | 1195 | ||
1208 | /* Process the incoming packet */ | 1196 | /* Process the incoming packet */ |
1209 | if (unlikely(!link_working_working(l_ptr))) { | 1197 | if (unlikely(!link_working_working(l_ptr))) { |
@@ -1936,7 +1924,12 @@ void tipc_link_bundle_rcv(struct sk_buff *buf) | |||
1936 | } | 1924 | } |
1937 | omsg = buf_msg(obuf); | 1925 | omsg = buf_msg(obuf); |
1938 | pos += align(msg_size(omsg)); | 1926 | pos += align(msg_size(omsg)); |
1939 | if (msg_isdata(omsg) || (msg_user(omsg) == CONN_MANAGER)) { | 1927 | if (msg_isdata(omsg)) { |
1928 | if (unlikely(msg_type(omsg) == TIPC_MCAST_MSG)) | ||
1929 | tipc_sk_mcast_rcv(obuf); | ||
1930 | else | ||
1931 | tipc_sk_rcv(obuf); | ||
1932 | } else if (msg_user(omsg) == CONN_MANAGER) { | ||
1940 | tipc_sk_rcv(obuf); | 1933 | tipc_sk_rcv(obuf); |
1941 | } else if (msg_user(omsg) == NAME_DISTRIBUTOR) { | 1934 | } else if (msg_user(omsg) == NAME_DISTRIBUTOR) { |
1942 | tipc_named_rcv(obuf); | 1935 | tipc_named_rcv(obuf); |