aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorOctavian Purdila <opurdila@ixiacom.com>2008-07-15 03:49:11 -0400
committerDavid S. Miller <davem@davemloft.net>2008-07-15 03:49:11 -0400
commit2870c43d1795bcb40b12bad6456f07ad8e64b3de (patch)
treeb831144bdbca0d21a40446d40ed33db2d17415a0 /net
parentb9e40857682ecfc5bcd0356a23ff409883ffb982 (diff)
net: refactor tcp splice receive path to improve readability
- move all of the details on offsets, lengths and buffers into a single function instead of doing these operation from multiple places - use a bottom up approach: try to avoid details in the high level functions, introduce them gradually as we go deeper in the function call stack With helpful feedback from Jarek Poplawski. Signed-off-by: Octavian Purdila <opurdila@ixiacom.com> Acked-by: Jarek Poplawski <jarkao2@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/skbuff.c153
1 files changed, 61 insertions, 92 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 50a853f7cd8e..48a43727d12f 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1282,114 +1282,83 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,
1282 return 0; 1282 return 0;
1283} 1283}
1284 1284
1285/* 1285static inline void __segment_seek(struct page **page, unsigned int *poff,
1286 * Map linear and fragment data from the skb to spd. Returns number of 1286 unsigned int *plen, unsigned int off)
1287 * pages mapped. 1287{
1288 */ 1288 *poff += off;
1289static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset, 1289 *page += *poff / PAGE_SIZE;
1290 unsigned int *total_len, 1290 *poff = *poff % PAGE_SIZE;
1291 struct splice_pipe_desc *spd) 1291 *plen -= off;
1292{ 1292}
1293 unsigned int nr_pages = spd->nr_pages; 1293
1294 unsigned int poff, plen, len, toff, tlen; 1294static inline int __splice_segment(struct page *page, unsigned int poff,
1295 int headlen, seg, error = 0; 1295 unsigned int plen, unsigned int *off,
1296 1296 unsigned int *len, struct sk_buff *skb,
1297 toff = *offset; 1297 struct splice_pipe_desc *spd)
1298 tlen = *total_len; 1298{
1299 if (!tlen) { 1299 if (!*len)
1300 error = 1; 1300 return 1;
1301 goto err; 1301
1302 /* skip this segment if already processed */
1303 if (*off >= plen) {
1304 *off -= plen;
1305 return 0;
1302 } 1306 }
1303 1307
1304 /* 1308 /* ignore any bits we already processed */
1305 * if the offset is greater than the linear part, go directly to 1309 if (*off) {
1306 * the fragments. 1310 __segment_seek(&page, &poff, &plen, *off);
1307 */ 1311 *off = 0;
1308 headlen = skb_headlen(skb);
1309 if (toff >= headlen) {
1310 toff -= headlen;
1311 goto map_frag;
1312 } 1312 }
1313 1313
1314 /* 1314 do {
1315 * first map the linear region into the pages/partial map, skipping 1315 unsigned int flen = min(*len, plen);
1316 * any potential initial offset.
1317 */
1318 len = 0;
1319 while (len < headlen) {
1320 void *p = skb->data + len;
1321
1322 poff = (unsigned long) p & (PAGE_SIZE - 1);
1323 plen = min_t(unsigned int, headlen - len, PAGE_SIZE - poff);
1324 len += plen;
1325
1326 if (toff) {
1327 if (plen <= toff) {
1328 toff -= plen;
1329 continue;
1330 }
1331 plen -= toff;
1332 poff += toff;
1333 toff = 0;
1334 }
1335 1316
1336 plen = min(plen, tlen); 1317 /* the linear region may spread across several pages */
1337 if (!plen) 1318 flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
1338 break;
1339 1319
1340 /* 1320 if (spd_fill_page(spd, page, flen, poff, skb))
1341 * just jump directly to update and return, no point 1321 return 1;
1342 * in going over fragments when the output is full.
1343 */
1344 error = spd_fill_page(spd, virt_to_page(p), plen, poff, skb);
1345 if (error)
1346 goto done;
1347 1322
1348 tlen -= plen; 1323 __segment_seek(&page, &poff, &plen, flen);
1349 } 1324 *len -= flen;
1325
1326 } while (*len && plen);
1327
1328 return 0;
1329}
1330
1331/*
1332 * Map linear and fragment data from the skb to spd. It reports failure if the
1333 * pipe is full or if we already spliced the requested length.
1334 */
1335int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,
1336 unsigned int *len,
1337 struct splice_pipe_desc *spd)
1338{
1339 int seg;
1340
1341 /*
1342 * map the linear part
1343 */
1344 if (__splice_segment(virt_to_page(skb->data),
1345 (unsigned long) skb->data & (PAGE_SIZE - 1),
1346 skb_headlen(skb),
1347 offset, len, skb, spd))
1348 return 1;
1350 1349
1351 /* 1350 /*
1352 * then map the fragments 1351 * then map the fragments
1353 */ 1352 */
1354map_frag:
1355 for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) { 1353 for (seg = 0; seg < skb_shinfo(skb)->nr_frags; seg++) {
1356 const skb_frag_t *f = &skb_shinfo(skb)->frags[seg]; 1354 const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];
1357 1355
1358 plen = f->size; 1356 if (__splice_segment(f->page, f->page_offset, f->size,
1359 poff = f->page_offset; 1357 offset, len, skb, spd))
1360 1358 return 1;
1361 if (toff) {
1362 if (plen <= toff) {
1363 toff -= plen;
1364 continue;
1365 }
1366 plen -= toff;
1367 poff += toff;
1368 toff = 0;
1369 }
1370
1371 plen = min(plen, tlen);
1372 if (!plen)
1373 break;
1374
1375 error = spd_fill_page(spd, f->page, plen, poff, skb);
1376 if (error)
1377 break;
1378
1379 tlen -= plen;
1380 } 1359 }
1381 1360
1382done: 1361 return 0;
1383 if (spd->nr_pages - nr_pages) {
1384 *offset = 0;
1385 *total_len = tlen;
1386 return 0;
1387 }
1388err:
1389 /* update the offset to reflect the linear part skip, if any */
1390 if (!error)
1391 *offset = toff;
1392 return error;
1393} 1362}
1394 1363
1395/* 1364/*