diff options
Diffstat (limited to 'net/tipc')
-rw-r--r-- | net/tipc/bcast.c | 7 | ||||
-rw-r--r-- | net/tipc/core.h | 5 | ||||
-rw-r--r-- | net/tipc/link.c | 119 | ||||
-rw-r--r-- | net/tipc/link.h | 7 | ||||
-rw-r--r-- | net/tipc/msg.c | 7 | ||||
-rw-r--r-- | net/tipc/msg.h | 1 | ||||
-rw-r--r-- | net/tipc/node.c | 12 | ||||
-rw-r--r-- | net/tipc/node.h | 4 | ||||
-rw-r--r-- | net/tipc/port.c | 2 | ||||
-rw-r--r-- | net/tipc/port.h | 4 | ||||
-rw-r--r-- | net/tipc/socket.c | 15 | ||||
-rw-r--r-- | net/tipc/socket.h | 7 |
12 files changed, 99 insertions, 91 deletions
diff --git a/net/tipc/bcast.c b/net/tipc/bcast.c index dd13bfa09333..9510fb2df566 100644 --- a/net/tipc/bcast.c +++ b/net/tipc/bcast.c | |||
@@ -300,8 +300,8 @@ void tipc_bclink_acknowledge(struct tipc_node *n_ptr, u32 acked) | |||
300 | tipc_link_push_queue(bcl); | 300 | tipc_link_push_queue(bcl); |
301 | bclink_set_last_sent(); | 301 | bclink_set_last_sent(); |
302 | } | 302 | } |
303 | if (unlikely(released && !list_empty(&bcl->waiting_ports))) | 303 | if (unlikely(released && !skb_queue_empty(&bcl->waiting_sks))) |
304 | tipc_link_wakeup_ports(bcl, 0); | 304 | bclink->node.action_flags |= TIPC_WAKEUP_USERS; |
305 | exit: | 305 | exit: |
306 | tipc_bclink_unlock(); | 306 | tipc_bclink_unlock(); |
307 | } | 307 | } |
@@ -840,9 +840,10 @@ int tipc_bclink_init(void) | |||
840 | sprintf(bcbearer->media.name, "tipc-broadcast"); | 840 | sprintf(bcbearer->media.name, "tipc-broadcast"); |
841 | 841 | ||
842 | spin_lock_init(&bclink->lock); | 842 | spin_lock_init(&bclink->lock); |
843 | INIT_LIST_HEAD(&bcl->waiting_ports); | 843 | __skb_queue_head_init(&bcl->waiting_sks); |
844 | bcl->next_out_no = 1; | 844 | bcl->next_out_no = 1; |
845 | spin_lock_init(&bclink->node.lock); | 845 | spin_lock_init(&bclink->node.lock); |
846 | __skb_queue_head_init(&bclink->node.waiting_sks); | ||
846 | bcl->owner = &bclink->node; | 847 | bcl->owner = &bclink->node; |
847 | bcl->max_pkt = MAX_PKT_DEFAULT_MCAST; | 848 | bcl->max_pkt = MAX_PKT_DEFAULT_MCAST; |
848 | tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); | 849 | tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT); |
diff --git a/net/tipc/core.h b/net/tipc/core.h index bb26ed1ee966..d2607a8e2b80 100644 --- a/net/tipc/core.h +++ b/net/tipc/core.h | |||
@@ -187,8 +187,11 @@ static inline void k_term_timer(struct timer_list *timer) | |||
187 | 187 | ||
188 | struct tipc_skb_cb { | 188 | struct tipc_skb_cb { |
189 | void *handle; | 189 | void *handle; |
190 | bool deferred; | ||
191 | struct sk_buff *tail; | 190 | struct sk_buff *tail; |
191 | bool deferred; | ||
192 | bool wakeup_pending; | ||
193 | u16 chain_sz; | ||
194 | u16 chain_imp; | ||
192 | }; | 195 | }; |
193 | 196 | ||
194 | #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) | 197 | #define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0])) |
diff --git a/net/tipc/link.c b/net/tipc/link.c index fb1485dc6736..6c775a107a02 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c | |||
@@ -275,7 +275,7 @@ struct tipc_link *tipc_link_create(struct tipc_node *n_ptr, | |||
275 | link_init_max_pkt(l_ptr); | 275 | link_init_max_pkt(l_ptr); |
276 | 276 | ||
277 | l_ptr->next_out_no = 1; | 277 | l_ptr->next_out_no = 1; |
278 | INIT_LIST_HEAD(&l_ptr->waiting_ports); | 278 | __skb_queue_head_init(&l_ptr->waiting_sks); |
279 | 279 | ||
280 | link_reset_statistics(l_ptr); | 280 | link_reset_statistics(l_ptr); |
281 | 281 | ||
@@ -322,66 +322,47 @@ void tipc_link_delete_list(unsigned int bearer_id, bool shutting_down) | |||
322 | } | 322 | } |
323 | 323 | ||
324 | /** | 324 | /** |
325 | * link_schedule_port - schedule port for deferred sending | 325 | * link_schedule_user - schedule user for wakeup after congestion |
326 | * @l_ptr: pointer to link | 326 | * @link: congested link |
327 | * @origport: reference to sending port | 327 | * @oport: sending port |
328 | * @sz: amount of data to be sent | 328 | * @chain_sz: size of buffer chain that was attempted sent |
329 | * | 329 | * @imp: importance of message attempted sent |
330 | * Schedules port for renewed sending of messages after link congestion | 330 | * Create pseudo msg to send back to user when congestion abates |
331 | * has abated. | ||
332 | */ | 331 | */ |
333 | static int link_schedule_port(struct tipc_link *l_ptr, u32 origport, u32 sz) | 332 | static bool link_schedule_user(struct tipc_link *link, u32 oport, |
333 | uint chain_sz, uint imp) | ||
334 | { | 334 | { |
335 | struct tipc_port *p_ptr; | 335 | struct sk_buff *buf; |
336 | struct tipc_sock *tsk; | ||
337 | 336 | ||
338 | spin_lock_bh(&tipc_port_list_lock); | 337 | buf = tipc_msg_create(SOCK_WAKEUP, 0, INT_H_SIZE, 0, tipc_own_addr, |
339 | p_ptr = tipc_port_lock(origport); | 338 | tipc_own_addr, oport, 0, 0); |
340 | if (p_ptr) { | 339 | if (!buf) |
341 | if (!list_empty(&p_ptr->wait_list)) | 340 | return false; |
342 | goto exit; | 341 | TIPC_SKB_CB(buf)->chain_sz = chain_sz; |
343 | tsk = tipc_port_to_sock(p_ptr); | 342 | TIPC_SKB_CB(buf)->chain_imp = imp; |
344 | tsk->link_cong = 1; | 343 | __skb_queue_tail(&link->waiting_sks, buf); |
345 | p_ptr->waiting_pkts = 1 + ((sz - 1) / l_ptr->max_pkt); | 344 | link->stats.link_congs++; |
346 | list_add_tail(&p_ptr->wait_list, &l_ptr->waiting_ports); | 345 | 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 | } | 346 | } |
354 | 347 | ||
355 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all) | 348 | /** |
349 | * link_prepare_wakeup - prepare users for wakeup after congestion | ||
350 | * @link: congested link | ||
351 | * Move a number of waiting users, as permitted by available space in | ||
352 | * the send queue, from link wait queue to node wait queue for wakeup | ||
353 | */ | ||
354 | static void link_prepare_wakeup(struct tipc_link *link) | ||
356 | { | 355 | { |
357 | struct tipc_port *p_ptr; | 356 | struct sk_buff_head *wq = &link->waiting_sks; |
358 | struct tipc_sock *tsk; | 357 | struct sk_buff *buf; |
359 | struct tipc_port *temp_p_ptr; | 358 | uint pend_qsz = link->out_queue_size; |
360 | int win = l_ptr->queue_limit[0] - l_ptr->out_queue_size; | 359 | |
361 | 360 | for (buf = skb_peek(wq); buf; buf = skb_peek(wq)) { | |
362 | if (all) | 361 | 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; | 362 | break; |
374 | tsk = tipc_port_to_sock(p_ptr); | 363 | pend_qsz += TIPC_SKB_CB(buf)->chain_sz; |
375 | list_del_init(&p_ptr->wait_list); | 364 | __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 | } | 365 | } |
382 | |||
383 | exit: | ||
384 | spin_unlock_bh(&tipc_port_list_lock); | ||
385 | } | 366 | } |
386 | 367 | ||
387 | /** | 368 | /** |
@@ -423,6 +404,7 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
423 | u32 prev_state = l_ptr->state; | 404 | u32 prev_state = l_ptr->state; |
424 | u32 checkpoint = l_ptr->next_in_no; | 405 | u32 checkpoint = l_ptr->next_in_no; |
425 | int was_active_link = tipc_link_is_active(l_ptr); | 406 | int was_active_link = tipc_link_is_active(l_ptr); |
407 | struct tipc_node *owner = l_ptr->owner; | ||
426 | 408 | ||
427 | msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); | 409 | msg_set_session(l_ptr->pmsg, ((msg_session(l_ptr->pmsg) + 1) & 0xffff)); |
428 | 410 | ||
@@ -450,9 +432,10 @@ void tipc_link_reset(struct tipc_link *l_ptr) | |||
450 | kfree_skb(l_ptr->proto_msg_queue); | 432 | kfree_skb(l_ptr->proto_msg_queue); |
451 | l_ptr->proto_msg_queue = NULL; | 433 | l_ptr->proto_msg_queue = NULL; |
452 | kfree_skb_list(l_ptr->oldest_deferred_in); | 434 | kfree_skb_list(l_ptr->oldest_deferred_in); |
453 | if (!list_empty(&l_ptr->waiting_ports)) | 435 | if (!skb_queue_empty(&l_ptr->waiting_sks)) { |
454 | tipc_link_wakeup_ports(l_ptr, 1); | 436 | skb_queue_splice_init(&l_ptr->waiting_sks, &owner->waiting_sks); |
455 | 437 | owner->action_flags |= TIPC_WAKEUP_USERS; | |
438 | } | ||
456 | l_ptr->retransm_queue_head = 0; | 439 | l_ptr->retransm_queue_head = 0; |
457 | l_ptr->retransm_queue_size = 0; | 440 | l_ptr->retransm_queue_size = 0; |
458 | l_ptr->last_out = NULL; | 441 | l_ptr->last_out = NULL; |
@@ -688,19 +671,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) | 671 | static int tipc_link_cong(struct tipc_link *link, struct sk_buff *buf) |
689 | { | 672 | { |
690 | struct tipc_msg *msg = buf_msg(buf); | 673 | struct tipc_msg *msg = buf_msg(buf); |
691 | uint psz = msg_size(msg); | ||
692 | uint imp = tipc_msg_tot_importance(msg); | 674 | uint imp = tipc_msg_tot_importance(msg); |
693 | u32 oport = msg_tot_origport(msg); | 675 | u32 oport = msg_tot_origport(msg); |
694 | 676 | ||
695 | if (likely(imp <= TIPC_CRITICAL_IMPORTANCE)) { | 677 | 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); | 678 | pr_warn("%s<%s>, send queue full", link_rst_msg, link->name); |
702 | tipc_link_reset(link); | 679 | tipc_link_reset(link); |
680 | goto drop; | ||
703 | } | 681 | } |
682 | if (unlikely(msg_errcode(msg))) | ||
683 | goto drop; | ||
684 | if (unlikely(msg_reroute_cnt(msg))) | ||
685 | goto drop; | ||
686 | if (TIPC_SKB_CB(buf)->wakeup_pending) | ||
687 | return -ELINKCONG; | ||
688 | if (link_schedule_user(link, oport, TIPC_SKB_CB(buf)->chain_sz, imp)) | ||
689 | return -ELINKCONG; | ||
690 | drop: | ||
704 | kfree_skb_list(buf); | 691 | kfree_skb_list(buf); |
705 | return -EHOSTUNREACH; | 692 | return -EHOSTUNREACH; |
706 | } | 693 | } |
@@ -1202,8 +1189,10 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr) | |||
1202 | if (unlikely(l_ptr->next_out)) | 1189 | if (unlikely(l_ptr->next_out)) |
1203 | tipc_link_push_queue(l_ptr); | 1190 | tipc_link_push_queue(l_ptr); |
1204 | 1191 | ||
1205 | if (unlikely(!list_empty(&l_ptr->waiting_ports))) | 1192 | if (released && !skb_queue_empty(&l_ptr->waiting_sks)) { |
1206 | tipc_link_wakeup_ports(l_ptr, 0); | 1193 | link_prepare_wakeup(l_ptr); |
1194 | l_ptr->owner->action_flags |= TIPC_WAKEUP_USERS; | ||
1195 | } | ||
1207 | 1196 | ||
1208 | /* Process the incoming packet */ | 1197 | /* Process the incoming packet */ |
1209 | if (unlikely(!link_working_working(l_ptr))) { | 1198 | if (unlikely(!link_working_working(l_ptr))) { |
diff --git a/net/tipc/link.h b/net/tipc/link.h index 782983ccd323..b567a3427fda 100644 --- a/net/tipc/link.h +++ b/net/tipc/link.h | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * net/tipc/link.h: Include file for TIPC link code | 2 | * net/tipc/link.h: Include file for TIPC link code |
3 | * | 3 | * |
4 | * Copyright (c) 1995-2006, 2013, Ericsson AB | 4 | * Copyright (c) 1995-2006, 2013-2014, Ericsson AB |
5 | * Copyright (c) 2004-2005, 2010-2011, Wind River Systems | 5 | * Copyright (c) 2004-2005, 2010-2011, Wind River Systems |
6 | * All rights reserved. | 6 | * All rights reserved. |
7 | * | 7 | * |
@@ -133,7 +133,7 @@ struct tipc_stats { | |||
133 | * @retransm_queue_size: number of messages to retransmit | 133 | * @retransm_queue_size: number of messages to retransmit |
134 | * @retransm_queue_head: sequence number of first message to retransmit | 134 | * @retransm_queue_head: sequence number of first message to retransmit |
135 | * @next_out: ptr to first unsent outbound message in queue | 135 | * @next_out: ptr to first unsent outbound message in queue |
136 | * @waiting_ports: linked list of ports waiting for link congestion to abate | 136 | * @waiting_sks: linked list of sockets waiting for link congestion to abate |
137 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages | 137 | * @long_msg_seq_no: next identifier to use for outbound fragmented messages |
138 | * @reasm_buf: head of partially reassembled inbound message fragments | 138 | * @reasm_buf: head of partially reassembled inbound message fragments |
139 | * @stats: collects statistics regarding link activity | 139 | * @stats: collects statistics regarding link activity |
@@ -194,7 +194,7 @@ struct tipc_link { | |||
194 | u32 retransm_queue_size; | 194 | u32 retransm_queue_size; |
195 | u32 retransm_queue_head; | 195 | u32 retransm_queue_head; |
196 | struct sk_buff *next_out; | 196 | struct sk_buff *next_out; |
197 | struct list_head waiting_ports; | 197 | struct sk_buff_head waiting_sks; |
198 | 198 | ||
199 | /* Fragmentation/reassembly */ | 199 | /* Fragmentation/reassembly */ |
200 | u32 long_msg_seq_no; | 200 | u32 long_msg_seq_no; |
@@ -235,7 +235,6 @@ void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob, | |||
235 | void tipc_link_push_queue(struct tipc_link *l_ptr); | 235 | void tipc_link_push_queue(struct tipc_link *l_ptr); |
236 | u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail, | 236 | u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail, |
237 | struct sk_buff *buf); | 237 | struct sk_buff *buf); |
238 | void tipc_link_wakeup_ports(struct tipc_link *l_ptr, int all); | ||
239 | void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window); | 238 | void tipc_link_set_queue_limits(struct tipc_link *l_ptr, u32 window); |
240 | void tipc_link_retransmit(struct tipc_link *l_ptr, | 239 | void tipc_link_retransmit(struct tipc_link *l_ptr, |
241 | struct sk_buff *start, u32 retransmits); | 240 | struct sk_buff *start, u32 retransmits); |
diff --git a/net/tipc/msg.c b/net/tipc/msg.c index fdb92e247050..74745a47d72a 100644 --- a/net/tipc/msg.c +++ b/net/tipc/msg.c | |||
@@ -182,7 +182,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | |||
182 | struct sk_buff *buf, *prev; | 182 | struct sk_buff *buf, *prev; |
183 | char *pktpos; | 183 | char *pktpos; |
184 | int rc; | 184 | int rc; |
185 | 185 | uint chain_sz = 0; | |
186 | msg_set_size(mhdr, msz); | 186 | msg_set_size(mhdr, msz); |
187 | 187 | ||
188 | /* No fragmentation needed? */ | 188 | /* No fragmentation needed? */ |
@@ -193,6 +193,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | |||
193 | return -ENOMEM; | 193 | return -ENOMEM; |
194 | skb_copy_to_linear_data(buf, mhdr, mhsz); | 194 | skb_copy_to_linear_data(buf, mhdr, mhsz); |
195 | pktpos = buf->data + mhsz; | 195 | pktpos = buf->data + mhsz; |
196 | TIPC_SKB_CB(buf)->chain_sz = 1; | ||
196 | if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) | 197 | if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz)) |
197 | return dsz; | 198 | return dsz; |
198 | rc = -EFAULT; | 199 | rc = -EFAULT; |
@@ -209,6 +210,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | |||
209 | *chain = buf = tipc_buf_acquire(pktmax); | 210 | *chain = buf = tipc_buf_acquire(pktmax); |
210 | if (!buf) | 211 | if (!buf) |
211 | return -ENOMEM; | 212 | return -ENOMEM; |
213 | chain_sz = 1; | ||
212 | pktpos = buf->data; | 214 | pktpos = buf->data; |
213 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); | 215 | skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE); |
214 | pktpos += INT_H_SIZE; | 216 | pktpos += INT_H_SIZE; |
@@ -242,6 +244,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | |||
242 | rc = -ENOMEM; | 244 | rc = -ENOMEM; |
243 | goto error; | 245 | goto error; |
244 | } | 246 | } |
247 | chain_sz++; | ||
245 | prev->next = buf; | 248 | prev->next = buf; |
246 | msg_set_type(&pkthdr, FRAGMENT); | 249 | msg_set_type(&pkthdr, FRAGMENT); |
247 | msg_set_size(&pkthdr, pktsz); | 250 | msg_set_size(&pkthdr, pktsz); |
@@ -251,7 +254,7 @@ int tipc_msg_build(struct tipc_msg *mhdr, struct iovec const *iov, | |||
251 | pktrem = pktsz - INT_H_SIZE; | 254 | pktrem = pktsz - INT_H_SIZE; |
252 | 255 | ||
253 | } while (1); | 256 | } while (1); |
254 | 257 | TIPC_SKB_CB(*chain)->chain_sz = chain_sz; | |
255 | msg_set_type(buf_msg(buf), LAST_FRAGMENT); | 258 | msg_set_type(buf_msg(buf), LAST_FRAGMENT); |
256 | return dsz; | 259 | return dsz; |
257 | error: | 260 | error: |
diff --git a/net/tipc/msg.h b/net/tipc/msg.h index 3045b2cfbff8..0ea7b695ac4d 100644 --- a/net/tipc/msg.h +++ b/net/tipc/msg.h | |||
@@ -442,6 +442,7 @@ static inline struct tipc_msg *msg_get_wrapped(struct tipc_msg *m) | |||
442 | #define NAME_DISTRIBUTOR 11 | 442 | #define NAME_DISTRIBUTOR 11 |
443 | #define MSG_FRAGMENTER 12 | 443 | #define MSG_FRAGMENTER 12 |
444 | #define LINK_CONFIG 13 | 444 | #define LINK_CONFIG 13 |
445 | #define SOCK_WAKEUP 14 /* pseudo user */ | ||
445 | 446 | ||
446 | /* | 447 | /* |
447 | * Connection management protocol message types | 448 | * Connection management protocol message types |
diff --git a/net/tipc/node.c b/net/tipc/node.c index f7069299943f..6ea2c15cfc88 100644 --- a/net/tipc/node.c +++ b/net/tipc/node.c | |||
@@ -38,6 +38,7 @@ | |||
38 | #include "config.h" | 38 | #include "config.h" |
39 | #include "node.h" | 39 | #include "node.h" |
40 | #include "name_distr.h" | 40 | #include "name_distr.h" |
41 | #include "socket.h" | ||
41 | 42 | ||
42 | #define NODE_HTABLE_SIZE 512 | 43 | #define NODE_HTABLE_SIZE 512 |
43 | 44 | ||
@@ -100,6 +101,7 @@ struct tipc_node *tipc_node_create(u32 addr) | |||
100 | INIT_HLIST_NODE(&n_ptr->hash); | 101 | INIT_HLIST_NODE(&n_ptr->hash); |
101 | INIT_LIST_HEAD(&n_ptr->list); | 102 | INIT_LIST_HEAD(&n_ptr->list); |
102 | INIT_LIST_HEAD(&n_ptr->nsub); | 103 | INIT_LIST_HEAD(&n_ptr->nsub); |
104 | __skb_queue_head_init(&n_ptr->waiting_sks); | ||
103 | 105 | ||
104 | hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); | 106 | hlist_add_head_rcu(&n_ptr->hash, &node_htable[tipc_hashfn(addr)]); |
105 | 107 | ||
@@ -474,6 +476,7 @@ int tipc_node_get_linkname(u32 bearer_id, u32 addr, char *linkname, size_t len) | |||
474 | void tipc_node_unlock(struct tipc_node *node) | 476 | void tipc_node_unlock(struct tipc_node *node) |
475 | { | 477 | { |
476 | LIST_HEAD(nsub_list); | 478 | LIST_HEAD(nsub_list); |
479 | struct sk_buff_head waiting_sks; | ||
477 | u32 addr = 0; | 480 | u32 addr = 0; |
478 | 481 | ||
479 | if (likely(!node->action_flags)) { | 482 | if (likely(!node->action_flags)) { |
@@ -481,6 +484,11 @@ void tipc_node_unlock(struct tipc_node *node) | |||
481 | return; | 484 | return; |
482 | } | 485 | } |
483 | 486 | ||
487 | __skb_queue_head_init(&waiting_sks); | ||
488 | if (node->action_flags & TIPC_WAKEUP_USERS) { | ||
489 | skb_queue_splice_init(&node->waiting_sks, &waiting_sks); | ||
490 | node->action_flags &= ~TIPC_WAKEUP_USERS; | ||
491 | } | ||
484 | if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { | 492 | if (node->action_flags & TIPC_NOTIFY_NODE_DOWN) { |
485 | list_replace_init(&node->nsub, &nsub_list); | 493 | list_replace_init(&node->nsub, &nsub_list); |
486 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; | 494 | node->action_flags &= ~TIPC_NOTIFY_NODE_DOWN; |
@@ -491,8 +499,12 @@ void tipc_node_unlock(struct tipc_node *node) | |||
491 | } | 499 | } |
492 | spin_unlock_bh(&node->lock); | 500 | spin_unlock_bh(&node->lock); |
493 | 501 | ||
502 | while (!skb_queue_empty(&waiting_sks)) | ||
503 | tipc_sk_rcv(__skb_dequeue(&waiting_sks)); | ||
504 | |||
494 | if (!list_empty(&nsub_list)) | 505 | if (!list_empty(&nsub_list)) |
495 | tipc_nodesub_notify(&nsub_list); | 506 | tipc_nodesub_notify(&nsub_list); |
507 | |||
496 | if (addr) | 508 | if (addr) |
497 | tipc_named_node_up(addr); | 509 | tipc_named_node_up(addr); |
498 | } | 510 | } |
diff --git a/net/tipc/node.h b/net/tipc/node.h index b61716a8218e..2ebf9e8b50fd 100644 --- a/net/tipc/node.h +++ b/net/tipc/node.h | |||
@@ -58,7 +58,8 @@ enum { | |||
58 | TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1), | 58 | TIPC_WAIT_PEER_LINKS_DOWN = (1 << 1), |
59 | TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2), | 59 | TIPC_WAIT_OWN_LINKS_DOWN = (1 << 2), |
60 | TIPC_NOTIFY_NODE_DOWN = (1 << 3), | 60 | TIPC_NOTIFY_NODE_DOWN = (1 << 3), |
61 | TIPC_NOTIFY_NODE_UP = (1 << 4) | 61 | TIPC_NOTIFY_NODE_UP = (1 << 4), |
62 | TIPC_WAKEUP_USERS = (1 << 5) | ||
62 | }; | 63 | }; |
63 | 64 | ||
64 | /** | 65 | /** |
@@ -115,6 +116,7 @@ struct tipc_node { | |||
115 | int working_links; | 116 | int working_links; |
116 | u32 signature; | 117 | u32 signature; |
117 | struct list_head nsub; | 118 | struct list_head nsub; |
119 | struct sk_buff_head waiting_sks; | ||
118 | struct rcu_head rcu; | 120 | struct rcu_head rcu; |
119 | }; | 121 | }; |
120 | 122 | ||
diff --git a/net/tipc/port.c b/net/tipc/port.c index 7e096a5e7701..b58a777a4399 100644 --- a/net/tipc/port.c +++ b/net/tipc/port.c | |||
@@ -92,7 +92,6 @@ u32 tipc_port_init(struct tipc_port *p_ptr, | |||
92 | 92 | ||
93 | p_ptr->max_pkt = MAX_PKT_DEFAULT; | 93 | p_ptr->max_pkt = MAX_PKT_DEFAULT; |
94 | p_ptr->ref = ref; | 94 | p_ptr->ref = ref; |
95 | INIT_LIST_HEAD(&p_ptr->wait_list); | ||
96 | INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); | 95 | INIT_LIST_HEAD(&p_ptr->subscription.nodesub_list); |
97 | k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); | 96 | k_init_timer(&p_ptr->timer, (Handler)port_timeout, ref); |
98 | INIT_LIST_HEAD(&p_ptr->publications); | 97 | INIT_LIST_HEAD(&p_ptr->publications); |
@@ -134,7 +133,6 @@ void tipc_port_destroy(struct tipc_port *p_ptr) | |||
134 | } | 133 | } |
135 | spin_lock_bh(&tipc_port_list_lock); | 134 | spin_lock_bh(&tipc_port_list_lock); |
136 | list_del(&p_ptr->port_list); | 135 | list_del(&p_ptr->port_list); |
137 | list_del(&p_ptr->wait_list); | ||
138 | spin_unlock_bh(&tipc_port_list_lock); | 136 | spin_unlock_bh(&tipc_port_list_lock); |
139 | k_term_timer(&p_ptr->timer); | 137 | k_term_timer(&p_ptr->timer); |
140 | } | 138 | } |
diff --git a/net/tipc/port.h b/net/tipc/port.h index 3087da39ee47..6cdc7de8c9b8 100644 --- a/net/tipc/port.h +++ b/net/tipc/port.h | |||
@@ -58,8 +58,6 @@ | |||
58 | * @ref: unique reference to port in TIPC object registry | 58 | * @ref: unique reference to port in TIPC object registry |
59 | * @phdr: preformatted message header used when sending messages | 59 | * @phdr: preformatted message header used when sending messages |
60 | * @port_list: adjacent ports in TIPC's global list of ports | 60 | * @port_list: adjacent ports in TIPC's global list of ports |
61 | * @wait_list: adjacent ports in list of ports waiting on link congestion | ||
62 | * @waiting_pkts: | ||
63 | * @publications: list of publications for port | 61 | * @publications: list of publications for port |
64 | * @pub_count: total # of publications port has made during its lifetime | 62 | * @pub_count: total # of publications port has made during its lifetime |
65 | * @probing_state: | 63 | * @probing_state: |
@@ -77,8 +75,6 @@ struct tipc_port { | |||
77 | u32 ref; | 75 | u32 ref; |
78 | struct tipc_msg phdr; | 76 | struct tipc_msg phdr; |
79 | struct list_head port_list; | 77 | struct list_head port_list; |
80 | struct list_head wait_list; | ||
81 | u32 waiting_pkts; | ||
82 | struct list_head publications; | 78 | struct list_head publications; |
83 | u32 pub_count; | 79 | u32 pub_count; |
84 | u32 probing_state; | 80 | u32 probing_state; |
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index ff8c8118d56e..a8be4d2001f7 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -579,6 +579,7 @@ new_mtu: | |||
579 | goto new_mtu; | 579 | goto new_mtu; |
580 | if (rc != -ELINKCONG) | 580 | if (rc != -ELINKCONG) |
581 | break; | 581 | break; |
582 | tipc_sk(sk)->link_cong = 1; | ||
582 | rc = tipc_wait_for_sndmsg(sock, &timeo); | 583 | rc = tipc_wait_for_sndmsg(sock, &timeo); |
583 | if (rc) | 584 | if (rc) |
584 | kfree_skb_list(buf); | 585 | kfree_skb_list(buf); |
@@ -651,7 +652,7 @@ static int tipc_sk_proto_rcv(struct tipc_sock *tsk, u32 *dnode, | |||
651 | conn_cong = tipc_sk_conn_cong(tsk); | 652 | conn_cong = tipc_sk_conn_cong(tsk); |
652 | tsk->sent_unacked -= msg_msgcnt(msg); | 653 | tsk->sent_unacked -= msg_msgcnt(msg); |
653 | if (conn_cong) | 654 | if (conn_cong) |
654 | tipc_sock_wakeup(tsk); | 655 | tsk->sk.sk_write_space(&tsk->sk); |
655 | } else if (msg_type(msg) == CONN_PROBE) { | 656 | } else if (msg_type(msg) == CONN_PROBE) { |
656 | if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) | 657 | if (!tipc_msg_reverse(buf, dnode, TIPC_OK)) |
657 | return TIPC_OK; | 658 | return TIPC_OK; |
@@ -826,6 +827,7 @@ new_mtu: | |||
826 | goto exit; | 827 | goto exit; |
827 | 828 | ||
828 | do { | 829 | do { |
830 | TIPC_SKB_CB(buf)->wakeup_pending = tsk->link_cong; | ||
829 | rc = tipc_link_xmit(buf, dnode, tsk->port.ref); | 831 | rc = tipc_link_xmit(buf, dnode, tsk->port.ref); |
830 | if (likely(rc >= 0)) { | 832 | if (likely(rc >= 0)) { |
831 | if (sock->state != SS_READY) | 833 | if (sock->state != SS_READY) |
@@ -835,10 +837,9 @@ new_mtu: | |||
835 | } | 837 | } |
836 | if (rc == -EMSGSIZE) | 838 | if (rc == -EMSGSIZE) |
837 | goto new_mtu; | 839 | goto new_mtu; |
838 | |||
839 | if (rc != -ELINKCONG) | 840 | if (rc != -ELINKCONG) |
840 | break; | 841 | break; |
841 | 842 | tsk->link_cong = 1; | |
842 | rc = tipc_wait_for_sndmsg(sock, &timeo); | 843 | rc = tipc_wait_for_sndmsg(sock, &timeo); |
843 | if (rc) | 844 | if (rc) |
844 | kfree_skb_list(buf); | 845 | kfree_skb_list(buf); |
@@ -953,6 +954,7 @@ next: | |||
953 | } | 954 | } |
954 | if (rc != -ELINKCONG) | 955 | if (rc != -ELINKCONG) |
955 | break; | 956 | break; |
957 | tsk->link_cong = 1; | ||
956 | } | 958 | } |
957 | rc = tipc_wait_for_sndpkt(sock, &timeo); | 959 | rc = tipc_wait_for_sndpkt(sock, &timeo); |
958 | if (rc) | 960 | if (rc) |
@@ -1518,6 +1520,13 @@ static int filter_rcv(struct sock *sk, struct sk_buff *buf) | |||
1518 | if (unlikely(msg_user(msg) == CONN_MANAGER)) | 1520 | if (unlikely(msg_user(msg) == CONN_MANAGER)) |
1519 | return tipc_sk_proto_rcv(tsk, &onode, buf); | 1521 | return tipc_sk_proto_rcv(tsk, &onode, buf); |
1520 | 1522 | ||
1523 | if (unlikely(msg_user(msg) == SOCK_WAKEUP)) { | ||
1524 | kfree_skb(buf); | ||
1525 | tsk->link_cong = 0; | ||
1526 | sk->sk_write_space(sk); | ||
1527 | return TIPC_OK; | ||
1528 | } | ||
1529 | |||
1521 | /* Reject message if it is wrong sort of message for socket */ | 1530 | /* Reject message if it is wrong sort of message for socket */ |
1522 | if (msg_type(msg) > TIPC_DIRECT_MSG) | 1531 | if (msg_type(msg) > TIPC_DIRECT_MSG) |
1523 | return -TIPC_ERR_NO_PORT; | 1532 | return -TIPC_ERR_NO_PORT; |
diff --git a/net/tipc/socket.h b/net/tipc/socket.h index 43b75b3ceced..1405633362f5 100644 --- a/net/tipc/socket.h +++ b/net/tipc/socket.h | |||
@@ -58,7 +58,7 @@ struct tipc_sock { | |||
58 | struct tipc_port port; | 58 | struct tipc_port port; |
59 | unsigned int conn_timeout; | 59 | unsigned int conn_timeout; |
60 | atomic_t dupl_rcvcnt; | 60 | atomic_t dupl_rcvcnt; |
61 | int link_cong; | 61 | bool link_cong; |
62 | uint sent_unacked; | 62 | uint sent_unacked; |
63 | uint rcv_unacked; | 63 | uint rcv_unacked; |
64 | }; | 64 | }; |
@@ -73,11 +73,6 @@ static inline struct tipc_sock *tipc_port_to_sock(const struct tipc_port *port) | |||
73 | return container_of(port, struct tipc_sock, port); | 73 | return container_of(port, struct tipc_sock, port); |
74 | } | 74 | } |
75 | 75 | ||
76 | static inline void tipc_sock_wakeup(struct tipc_sock *tsk) | ||
77 | { | ||
78 | tsk->sk.sk_write_space(&tsk->sk); | ||
79 | } | ||
80 | |||
81 | static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) | 76 | static inline int tipc_sk_conn_cong(struct tipc_sock *tsk) |
82 | { | 77 | { |
83 | return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; | 78 | return tsk->sent_unacked >= TIPC_FLOWCTRL_WIN; |