[PATCH] splice: fix offset problems

Make the move_from_pipe() actors return number of bytes processed, then
move_from_pipe() can decide more cleverly when to move on to the next
buffer.

This fixes problems with pipe offset and differing file offset.

Signed-off-by: Jens Axboe <axboe@suse.de>

authored by Jens Axboe and committed by Jens Axboe 016b661e ba5f5d90

+27 -19
+27 -19
fs/splice.c
··· 439 439 440 440 /* 441 441 * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' 442 - * using sendpage(). 442 + * using sendpage(). Return the number of bytes sent. 443 443 */ 444 444 static int pipe_to_sendpage(struct pipe_inode_info *info, 445 445 struct pipe_buffer *buf, struct splice_desc *sd) 446 446 { 447 447 struct file *file = sd->file; 448 448 loff_t pos = sd->pos; 449 - unsigned int offset; 450 449 ssize_t ret; 451 450 void *ptr; 452 451 int more; ··· 460 461 if (IS_ERR(ptr)) 461 462 return PTR_ERR(ptr); 462 463 463 - offset = pos & ~PAGE_CACHE_MASK; 464 464 more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; 465 465 466 - ret = file->f_op->sendpage(file, buf->page, offset, sd->len, &pos,more); 466 + ret = file->f_op->sendpage(file, buf->page, buf->offset, sd->len, 467 + &pos, more); 467 468 468 469 buf->ops->unmap(info, buf); 469 - if (ret == sd->len) 470 - return 0; 471 - 472 - return -EIO; 470 + return ret; 473 471 } 474 472 475 473 /* ··· 495 499 struct file *file = sd->file; 496 500 struct address_space *mapping = file->f_mapping; 497 501 gfp_t gfp_mask = mapping_gfp_mask(mapping); 498 - unsigned int offset; 502 + unsigned int offset, this_len; 499 503 struct page *page; 500 504 pgoff_t index; 501 505 char *src; ··· 510 514 511 515 index = sd->pos >> PAGE_CACHE_SHIFT; 512 516 offset = sd->pos & ~PAGE_CACHE_MASK; 517 + 518 + this_len = sd->len; 519 + if (this_len + offset > PAGE_CACHE_SIZE) 520 + this_len = PAGE_CACHE_SIZE - offset; 513 521 514 522 /* 515 523 * Reuse buf page, if SPLICE_F_MOVE is set. ··· 558 558 * the full page. 559 559 */ 560 560 if (!PageUptodate(page)) { 561 - if (sd->len < PAGE_CACHE_SIZE) { 561 + if (this_len < PAGE_CACHE_SIZE) { 562 562 ret = mapping->a_ops->readpage(file, page); 563 563 if (unlikely(ret)) 564 564 goto out; ··· 582 582 } 583 583 } 584 584 585 - ret = mapping->a_ops->prepare_write(file, page, 0, sd->len); 585 + ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); 586 586 if (ret == AOP_TRUNCATED_PAGE) { 587 587 page_cache_release(page); 588 588 goto find_page; ··· 592 592 if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) { 593 593 char *dst = kmap_atomic(page, KM_USER0); 594 594 595 - memcpy(dst + offset, src + buf->offset, sd->len); 595 + memcpy(dst + offset, src + buf->offset, this_len); 596 596 flush_dcache_page(page); 597 597 kunmap_atomic(dst, KM_USER0); 598 598 } 599 599 600 - ret = mapping->a_ops->commit_write(file, page, 0, sd->len); 600 + ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); 601 601 if (ret == AOP_TRUNCATED_PAGE) { 602 602 page_cache_release(page); 603 603 goto find_page; 604 604 } else if (ret) 605 605 goto out; 606 606 607 + /* 608 + * Return the number of bytes written. 609 + */ 610 + ret = this_len; 607 611 mark_page_accessed(page); 608 612 balance_dirty_pages_ratelimited(mapping); 609 613 out: ··· 656 652 sd.len = sd.total_len; 657 653 658 654 err = actor(pipe, buf, &sd); 659 - if (err) { 655 + if (err <= 0) { 660 656 if (!ret && err != -ENODATA) 661 657 ret = err; 662 658 663 659 break; 664 660 } 665 661 666 - ret += sd.len; 667 - buf->offset += sd.len; 668 - buf->len -= sd.len; 662 + ret += err; 663 + buf->offset += err; 664 + buf->len -= err; 665 + 666 + sd.len -= err; 667 + sd.pos += err; 668 + sd.total_len -= err; 669 + if (sd.len) 670 + continue; 669 671 670 672 if (!buf->len) { 671 673 buf->ops = NULL; ··· 682 672 do_wakeup = 1; 683 673 } 684 674 685 - sd.pos += sd.len; 686 - sd.total_len -= sd.len; 687 675 if (!sd.total_len) 688 676 break; 689 677 }