|
36 | 36 |
|
37 | 37 | #include "core.h"
|
38 | 38 | #include "link.h"
|
39 |
| -#include "port.h" |
40 | 39 | #include "socket.h"
|
41 | 40 | #include "name_distr.h"
|
42 | 41 | #include "discover.h"
|
@@ -275,7 +274,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr,
|
275 | 274 | link_init_max_pkt(l_ptr);
|
276 | 275 |
|
277 | 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 | 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 |
326 |
| - * @l_ptr: pointer to link |
327 |
| - * @origport: reference to sending port |
328 |
| - * @sz: amount of data to be sent |
329 |
| - * |
330 |
| - * Schedules port for renewed sending of messages after link congestion |
331 |
| - * has abated. |
| 324 | + * link_schedule_user - schedule user for wakeup after congestion |
| 325 | + * @link: congested link |
| 326 | + * @oport: sending port |
| 327 | + * @chain_sz: size of buffer chain that was attempted sent |
| 328 | + * @imp: importance of message attempted sent |
| 329 | + * Create pseudo msg to send back to user when congestion abates |
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; |
336 |
| - struct tipc_sock *tsk; |
| 334 | + struct sk_buff *buf; |
337 | 335 |
|
338 |
| - spin_lock_bh(&tipc_port_list_lock); |
339 |
| - p_ptr = tipc_port_lock(origport); |
340 |
| - if (p_ptr) { |
341 |
| - if (!list_empty(&p_ptr->wait_list)) |
342 |
| - goto exit; |
343 |
| - tsk = tipc_port_to_sock(p_ptr); |
344 |
| - tsk->link_cong = 1; |
345 |
| - p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); |
346 |
| - list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); |
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; |
| 336 | + buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr, |
| 337 | + tipc_own_addr, oport, 0, 0); |
| 338 | + if (!buf) |
| 339 | + return false; |
| 340 | + TIPC_SKB_CB(buf)->chain_sz = chain_sz; |
| 341 | + TIPC_SKB_CB(buf)->chain_imp = imp; |
| 342 | + __skb_queue_tail(&link->waiting_sks, buf); |
| 343 | + link->stats.link_congs++; |
| 344 | + return true; |
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; |
358 |
| - struct tipc_sock *tsk; |
359 |
| - struct tipc_port *temp_p_ptr; |
360 |
| - int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; |
361 |
| - |
362 |
| - if (all) |
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) |
| 355 | + struct sk_buff_head *wq = &link->waiting_sks; |
| 356 | + struct sk_buff *buf; |
| 357 | + uint pend_qsz = link->out_queue_size; |
| 358 | + |
| 359 | + for (buf = skb_peek(wq); buf; buf = skb_peek(wq)) { |
| 360 | + if (pend_qsz >= link->queue_limit[TIPC_SKB_CB(buf)->chain_imp]) |
373 | 361 | break;
|
374 |
| - tsk = tipc_port_to_sock(p_ptr); |
375 |
| - list_del_init(&p_ptr->wait_list); |
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); |
| 362 | + pend_qsz += TIPC_SKB_CB(buf)->chain_sz; |
| 363 | + __skb_queue_tail(&link->owner->waiting_sks, __skb_dequeue(wq)); |
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 | 403 | u32 prev_state = l_ptr->state;
|
424 | 404 | u32 checkpoint = l_ptr->next_in_no;
|
425 | 405 | int was_active_link = tipc_link_is_active(l_ptr);
|
| 406 | + struct tipc_node *owner = l_ptr->owner; |
426 | 407 |
|
427 | 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 | 431 | kfree_skb(l_ptr->proto_msg_queue);
|
451 | 432 | l_ptr->proto_msg_queue = NULL;
|
452 | 433 | kfree_skb_list(l_ptr->oldest_deferred_in);
|
453 |
| - if (!list_empty(&l_ptr->waiting_ports)) |
454 |
| - tipc_link_wakeup_ports(l_ptr, 1); |
455 |
| - |
| 434 | + if (!skb_queue_empty(&l_ptr->waiting_sks)) { |
| 435 | + skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks); |
| 436 | + owner->action_flags |= TIPC_WAKEUP_USERS; |
| 437 | + } |
456 | 438 | l_ptr->retransm_queue_head = 0;
|
457 | 439 | l_ptr->retransm_queue_size = 0;
|
458 | 440 | l_ptr->last_out = NULL;
|
@@ -688,19 +670,23 @@ static void link_state_event(struct tipc_link *l_ptr, unsigned int event)
|
688 | 670 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf)
|
689 | 671 | {
|
690 | 672 | struct tipc_msg *msg = buf_msg(buf);
|
691 |
| - uint psz = msg_size(msg); |
692 | 673 | uint imp = tipc_msg_tot_importance(msg);
|
693 | 674 | u32 oport = msg_tot_origport(msg);
|
694 | 675 |
|
695 |
| - if (likely(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 { |
| 676 | + if (unlikely(imp > TIPC_CRITICAL_IMPORTANCE)) { |
701 | 677 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name);
|
702 | 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 | 690 | kfree_skb_list(buf);
|
705 | 691 | return -EHOSTUNREACH;
|
706 | 692 | }
|
@@ -1202,8 +1188,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
|
1202 | 1188 | if (unlikely(l_ptr->next_out))
|
1203 | 1189 | tipc_link_push_queue(l_ptr);
|
1204 | 1190 |
|
1205 |
| - if (unlikely(!list_empty(&l_ptr->waiting_ports))) |
1206 |
| - tipc_link_wakeup_ports(l_ptr, 0); |
| 1191 | + if (released && !skb_queue_empty(&l_ptr->waiting_sks)) { |
| 1192 | + link_prepare_wakeup(l_ptr); |
| 1193 | + l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS; |
| 1194 | + } |
1207 | 1195 |
|
1208 | 1196 | /* Process the incoming packet */
|
1209 | 1197 | if (unlikely(!link_working_working(l_ptr))) {
|
|
0 commit comments