Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen: netback: handle compound page fragments on transmit.

An SKB paged fragment can consist of a compound page with order > 0.
However the netchannel protocol deals only in PAGE_SIZE frames.

Handle this in netbk_gop_frag_copy and xen_netbk_count_skb_slots by
iterating over the frames which make up the page.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Konrad Rzeszutek Wilk <konrad@kernel.org>
Cc: Sander Eikelenboom <linux@eikelenboom.it>
Tested-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ian Campbell and committed by
David S. Miller
6a8ed462 6caab7b0

+35 -5
+35 -5
drivers/net/xen-netback/netback.c
··· 335 335 336 336 for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 337 337 unsigned long size = skb_frag_size(&skb_shinfo(skb)->frags[i]); 338 + unsigned long offset = skb_shinfo(skb)->frags[i].page_offset; 338 339 unsigned long bytes; 340 + 341 + offset &= ~PAGE_MASK; 342 + 339 343 while (size > 0) { 344 + BUG_ON(offset >= PAGE_SIZE); 340 345 BUG_ON(copy_off > MAX_BUFFER_OFFSET); 341 346 342 - if (start_new_rx_buffer(copy_off, size, 0)) { 347 + bytes = PAGE_SIZE - offset; 348 + 349 + if (bytes > size) 350 + bytes = size; 351 + 352 + if (start_new_rx_buffer(copy_off, bytes, 0)) { 343 353 count++; 344 354 copy_off = 0; 345 355 } 346 356 347 - bytes = size; 348 357 if (copy_off + bytes > MAX_BUFFER_OFFSET) 349 358 bytes = MAX_BUFFER_OFFSET - copy_off; 350 359 351 360 copy_off += bytes; 361 + 362 + offset += bytes; 352 363 size -= bytes; 364 + 365 + if (offset == PAGE_SIZE) 366 + offset = 0; 353 367 } 354 368 } 355 369 return count; ··· 417 403 unsigned long bytes; 418 404 419 405 /* Data must not cross a page boundary. */ 420 - BUG_ON(size + offset > PAGE_SIZE); 406 + BUG_ON(size + offset > PAGE_SIZE<<compound_order(page)); 421 407 422 408 meta = npo->meta + npo->meta_prod - 1; 423 409 410 + /* Skip unused frames from start of page */ 411 + page += offset >> PAGE_SHIFT; 412 + offset &= ~PAGE_MASK; 413 + 424 414 while (size > 0) { 415 + BUG_ON(offset >= PAGE_SIZE); 425 416 BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET); 426 417 427 - if (start_new_rx_buffer(npo->copy_off, size, *head)) { 418 + bytes = PAGE_SIZE - offset; 419 + 420 + if (bytes > size) 421 + bytes = size; 422 + 423 + if (start_new_rx_buffer(npo->copy_off, bytes, *head)) { 428 424 /* 429 425 * Netfront requires there to be some data in the head 430 426 * buffer. ··· 444 420 meta = get_next_rx_buffer(vif, npo); 445 421 } 446 422 447 - bytes = size; 448 423 if (npo->copy_off + bytes > MAX_BUFFER_OFFSET) 449 424 bytes = MAX_BUFFER_OFFSET - npo->copy_off; 450 425 ··· 475 452 476 453 offset += bytes; 477 454 size -= bytes; 455 + 456 + /* Next frame */ 457 + if (offset == PAGE_SIZE && size) { 458 + BUG_ON(!PageCompound(page)); 459 + page++; 460 + offset = 0; 461 + } 478 462 479 463 /* Leave a gap for the GSO descriptor. */ 480 464 if (*head && skb_shinfo(skb)->gso_size && !vif->gso_prefix)