diff options
author | Octavian Purdila <opurdila@ixiacom.com> | 2008-07-15 03:49:11 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-07-15 03:49:11 -0400 |
commit | 2870c43d1795bcb40b12bad6456f07ad8e64b3de (patch) | |
tree | b831144bdbca0d21a40446d40ed33db2d17415a0 /net | |
parent | b9e40857682ecfc5bcd0356a23ff409883ffb982 (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.c | 153 |
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 | /* | 1285 | static 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; |
1289 | static 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; | 1294 | static 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 | */ | ||
1335 | int __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 | */ |
1354 | map_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 | ||
1382 | done: | 1361 | return 0; |
1383 | if (spd->nr_pages - nr_pages) { | ||
1384 | *offset = 0; | ||
1385 | *total_len = tlen; | ||
1386 | return 0; | ||
1387 | } | ||
1388 | err: | ||
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 | /* |