Commit 77561557 authored by Allan Stephens's avatar Allan Stephens Committed by Paul Gortmaker

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: default avatarAllan Stephens <allan.stephens@windriver.com>
Signed-off-by: default avatarPaul Gortmaker <paul.gortmaker@windriver.com>
parent e0f08596
...@@ -2406,6 +2406,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf) ...@@ -2406,6 +2406,8 @@ void tipc_link_recv_bundle(struct sk_buff *buf)
*/ */
static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
{ {
struct sk_buff *buf_chain = NULL;
struct sk_buff *buf_chain_tail = (struct sk_buff *)&buf_chain;
struct tipc_msg *inmsg = buf_msg(buf); struct tipc_msg *inmsg = buf_msg(buf);
struct tipc_msg fragm_hdr; struct tipc_msg fragm_hdr;
u32 insize = msg_size(inmsg); u32 insize = msg_size(inmsg);
...@@ -2414,7 +2416,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) ...@@ -2414,7 +2416,7 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
u32 rest = insize; u32 rest = insize;
u32 pack_sz = l_ptr->max_pkt; u32 pack_sz = l_ptr->max_pkt;
u32 fragm_sz = pack_sz - INT_H_SIZE; u32 fragm_sz = pack_sz - INT_H_SIZE;
u32 fragm_no = 1; u32 fragm_no = 0;
u32 destaddr; u32 destaddr;
if (msg_short(inmsg)) if (msg_short(inmsg))
...@@ -2426,9 +2428,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) ...@@ -2426,9 +2428,6 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT, tipc_msg_init(&fragm_hdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
INT_H_SIZE, destaddr); INT_H_SIZE, destaddr);
msg_set_long_msgno(&fragm_hdr, l_ptr->long_msg_seq_no++);
msg_set_fragm_no(&fragm_hdr, fragm_no);
l_ptr->stats.sent_fragmented++;
/* Chop up message: */ /* Chop up message: */
...@@ -2441,27 +2440,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf) ...@@ -2441,27 +2440,37 @@ static int link_send_long_buf(struct link *l_ptr, struct sk_buff *buf)
} }
fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE); fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE);
if (fragm == NULL) { if (fragm == NULL) {
warn("Link unable to fragment message\n"); buf_discard(buf);
dsz = -ENOMEM; while (buf_chain) {
goto exit; buf = buf_chain;
buf_chain = buf_chain->next;
buf_discard(buf);
}
return -ENOMEM;
} }
msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE); msg_set_size(&fragm_hdr, fragm_sz + INT_H_SIZE);
fragm_no++;
msg_set_fragm_no(&fragm_hdr, fragm_no);
skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE); skb_copy_to_linear_data(fragm, &fragm_hdr, INT_H_SIZE);
skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs, skb_copy_to_linear_data_offset(fragm, INT_H_SIZE, crs,
fragm_sz); fragm_sz);
/* Send queued messages first, if any: */ buf_chain_tail->next = fragm;
buf_chain_tail = fragm;
l_ptr->stats.sent_fragments++;
tipc_link_send_buf(l_ptr, fragm);
if (!tipc_link_is_up(l_ptr))
return dsz;
msg_set_fragm_no(&fragm_hdr, ++fragm_no);
rest -= fragm_sz; rest -= fragm_sz;
crs += fragm_sz; crs += fragm_sz;
msg_set_type(&fragm_hdr, FRAGMENT); msg_set_type(&fragm_hdr, FRAGMENT);
} }
exit:
buf_discard(buf); buf_discard(buf);
/* Append chain of fragments to send queue & send them */
l_ptr->long_msg_seq_no++;
link_add_chain_to_outqueue(l_ptr, buf_chain, l_ptr->long_msg_seq_no);
l_ptr->stats.sent_fragments += fragm_no;
l_ptr->stats.sent_fragmented++;
tipc_link_push_queue(l_ptr);
return dsz; return dsz;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment