aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc
diff options
context:
space:
mode:
authorAllan Stephens <allan.stephens@windriver.com>2011-04-17 13:06:23 -0400
committerPaul Gortmaker <paul.gortmaker@windriver.com>2011-05-10 16:03:49 -0400
commit77561557447d3be586e701815e261c93c11ded00 (patch)
treefcd67619694aac500aa3c9761bd16883437869a2 /net/tipc
parente0f085964cac97a3a9e47741365ef6a03e500873 (diff)
tipc: Fix issues with fragmentation of an existing message buffer
Modifies the routine that fragments an existing message buffer to use similar logic to that used when generating fragments from an iovec. The routine now creates a complete chain of fragments and adds them to the link transmit queue as a unit, so that the link sends all fragments or none; this prevents the incomplete transmission of a fragmented message that might otherwise result because of link congestion or memory exhaustion. This change also ensures that the counter recording the number of fragmented messages sent by the link is now incremented only if the message is actually sent. Signed-off-by: Allan Stephens <allan.stephens@windriver.com> Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
Diffstat (limited to 'net/tipc')
-rw-r--r--net/tipc/link.c37
1 files changed, 23 insertions, 14 deletions
diff --git a/net/tipc/link.c b/net/tipc/link.c
index ad356df12d1e..02b083e5c219 100644
--- a/net/tipc/link.c
+++ b/net/tipc/link.c
@@ -2406,6 +2406,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
2406 */ 2406 */
2407static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) 2407static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
2408{ 2408{
2409 struct sk_buff *buf_chain = NULL;
2410 struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain;
2409 struct tipc_msg *inmsg = buf_msg(buf); 2411 struct tipc_msg *inmsg = buf_msg(buf);
2410 struct tipc_msg fragm_hdr; 2412 struct tipc_msg fragm_hdr;
2411 u32 insize = msg_size(inmsg); 2413 u32 insize = msg_size(inmsg);
@@ -2414,7 +2416,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
2414 u32 rest = insize; 2416 u32 rest = insize;
2415 u32 pack_sz = l_ptr->max_pkt; 2417 u32 pack_sz = l_ptr->max_pkt;
2416 u32 fragm_sz = pack_sz - INT_H_SIZE; 2418 u32 fragm_sz = pack_sz - INT_H_SIZE;
2417 u32 fragm_no = 1; 2419 u32 fragm_no = 0;
2418 u32 destaddr; 2420 u32 destaddr;
2419 2421
2420 if (msg_short(inmsg)) 2422 if (msg_short(inmsg))
@@ -2426,9 +2428,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
2426 2428
2427 tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, 2429 tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
2428 INT_H_SIZE, destaddr); 2430 INT_H_SIZE, destaddr);
2429 msg_set_long_msgno(&fragm_hdr, l_ptr->long_msg_seq_no++);
2430 msg_set_fragm_no(&fragm_hdr, fragm_no);
2431 l_ptr->stats.sent_fragmented++;
2432 2431
2433 /* Chop up message: */ 2432 /* Chop up message: */
2434 2433
@@ -2441,27 +2440,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
2441 } 2440 }
2442 fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); 2441 fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE);
2443 if (fragm == NULL) { 2442 if (fragm == NULL) {
2444 warn("Link unable to fragment message\n"); 2443 buf_discard(buf);
2445 dsz = -ENOMEM; 2444 while (buf_chain) {
2446 goto exit; 2445 buf = buf_chain;
2446 buf_chain = buf_chain->next;
2447 buf_discard(buf);
2448 }
2449 return -ENOMEM;
2447 } 2450 }
2448 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); 2451 msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
2452 fragm_no++;
2453 msg_set_fragm_no(&fragm_hdr, fragm_no);
2449 skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); 2454 skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE);
2450 skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, 2455 skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs,
2451 fragm_sz); 2456 fragm_sz);
2452 /* Send queued messages first, if any: */ 2457 buf_chain_tail->next = fragm;
2458 buf_chain_tail = fragm;
2453 2459
2454 l_ptr->stats.sent_fragments++;
2455 tipc_link_send_buf(l_ptr, fragm);
2456 if (!tipc_link_is_up(l_ptr))
2457 return dsz;
2458 msg_set_fragm_no(&fragm_hdr, ++fragm_no);
2459 rest -= fragm_sz; 2460 rest -= fragm_sz;
2460 crs += fragm_sz; 2461 crs += fragm_sz;
2461 msg_set_type(&fragm_hdr, FRAGMENT); 2462 msg_set_type(&fragm_hdr, FRAGMENT);
2462 } 2463 }
2463exit:
2464 buf_discard(buf); 2464 buf_discard(buf);
2465
2466 /* Append chain of fragments to send queue & send them */
2467
2468 l_ptr->long_msg_seq_no++;
2469 link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no);
2470 l_ptr->stats.sent_fragments += fragm_no;
2471 l_ptr->stats.sent_fragmented++;
2472 tipc_link_push_queue(l_ptr);
2473
2465 return dsz; 2474 return dsz;
2466} 2475}
2467 2476