aboutsummaryrefslogtreecommitdiffstats
path: root/net/tipc/msg.c
diff options
context:
space:
mode:
authorJon Paul Maloy <jon.maloy@ericsson.com>2014-06-25 21:41:34 -0400
committerDavid S. Miller <davem@davemloft.net>2014-06-27 15:50:55 -0400
commit067608e9d019d6477fd45dd948e81af0e5bf599f (patch)
treecb6cdf5cd95365a97087e9baae2cb4e96a12710a /net/tipc/msg.c
parent16e166b88cdfd508b88934ec0c8a0ec97e6b30f8 (diff)
tipc: introduce direct iovec to buffer chain fragmentation function
Fragmentation at message sending is currently performed in two places in link.c, depending on whether data to be transmitted is delivered in the form of an iovec or as a big sk_buff. Those functions are also tightly entangled with the send functions that are using them. We now introduce a re-entrant, standalone function, tipc_msg_build2(), that builds a packet chain directly from an iovec. Each fragment is sized according to the MTU value given by the caller, and is prepended with a correctly built fragment header, when needed. The function is independent from who is calling and where the chain will be delivered, as long as the caller is able to indicate a correct MTU. The function is tested, but not called by anybody yet. Since it is incompatible with the existing tipc_msg_build(), and we cannot yet remove that function, we have given it a temporary name. Signed-off-by: Jon Maloy <jon.maloy@ericsson.com> Reviewed-by: Erik Hugne <erik.hugne@ericsson.com> Reviewed-by: Ying Xue <ying.xue@windriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/tipc/msg.c')
-rw-r--r--net/tipc/msg.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index e02afc96edd7..4093b4c94d26 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -144,6 +144,108 @@ out_free:
144 return 0; 144 return 0;
145} 145}
146 146
147
148/**
149 * tipc_msg_build2 - create buffer chain containing specified header and data
150 * @mhdr: Message header, to be prepended to data
151 * @iov: User data
152 * @offset: Posision in iov to start copying from
153 * @dsz: Total length of user data
154 * @pktmax: Max packet size that can be used
155 * @chain: Buffer or chain of buffers to be returned to caller
156 * Returns message data size or errno: -ENOMEM, -EFAULT
157 */
158int tipc_msg_build2(struct tipc_msg *mhdr, struct iovec const *iov,
159 int offset, int dsz, int pktmax , struct sk_buff **chain)
160{
161 int mhsz = msg_hdr_sz(mhdr);
162 int msz = mhsz + dsz;
163 int pktno = 1;
164 int pktsz;
165 int pktrem = pktmax;
166 int drem = dsz;
167 struct tipc_msg pkthdr;
168 struct sk_buff *buf, *prev;
169 char *pktpos;
170 int rc;
171
172 msg_set_size(mhdr, msz);
173
174 /* No fragmentation needed? */
175 if (likely(msz <= pktmax)) {
176 buf = tipc_buf_acquire(msz);
177 *chain = buf;
178 if (unlikely(!buf))
179 return -ENOMEM;
180 skb_copy_to_linear_data(buf, mhdr, mhsz);
181 pktpos = buf->data + mhsz;
182 if (!dsz || !memcpy_fromiovecend(pktpos, iov, offset, dsz))
183 return dsz;
184 rc = -EFAULT;
185 goto error;
186 }
187
188 /* Prepare reusable fragment header */
189 tipc_msg_init(&pkthdr, MSG_FRAGMENTER, FIRST_FRAGMENT,
190 INT_H_SIZE, msg_destnode(mhdr));
191 msg_set_size(&pkthdr, pktmax);
192 msg_set_fragm_no(&pkthdr, pktno);
193
194 /* Prepare first fragment */
195 *chain = buf = tipc_buf_acquire(pktmax);
196 if (!buf)
197 return -ENOMEM;
198 pktpos = buf->data;
199 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
200 pktpos += INT_H_SIZE;
201 pktrem -= INT_H_SIZE;
202 skb_copy_to_linear_data_offset(buf, INT_H_SIZE, mhdr, mhsz);
203 pktpos += mhsz;
204 pktrem -= mhsz;
205
206 do {
207 if (drem < pktrem)
208 pktrem = drem;
209
210 if (memcpy_fromiovecend(pktpos, iov, offset, pktrem)) {
211 rc = -EFAULT;
212 goto error;
213 }
214 drem -= pktrem;
215 offset += pktrem;
216
217 if (!drem)
218 break;
219
220 /* Prepare new fragment: */
221 if (drem < (pktmax - INT_H_SIZE))
222 pktsz = drem + INT_H_SIZE;
223 else
224 pktsz = pktmax;
225 prev = buf;
226 buf = tipc_buf_acquire(pktsz);
227 if (!buf) {
228 rc = -ENOMEM;
229 goto error;
230 }
231 prev->next = buf;
232 msg_set_type(&pkthdr, FRAGMENT);
233 msg_set_size(&pkthdr, pktsz);
234 msg_set_fragm_no(&pkthdr, ++pktno);
235 skb_copy_to_linear_data(buf, &pkthdr, INT_H_SIZE);
236 pktpos = buf->data + INT_H_SIZE;
237 pktrem = pktsz - INT_H_SIZE;
238
239 } while (1);
240
241 msg_set_type(buf_msg(buf), LAST_FRAGMENT);
242 return dsz;
243error:
244 kfree_skb_list(*chain);
245 *chain = NULL;
246 return rc;
247}
248
147/** 249/**
148 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one 250 * tipc_msg_bundle(): Append contents of a buffer to tail of an existing one
149 * @bbuf: the existing buffer ("bundle") 251 * @bbuf: the existing buffer ("bundle")