diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 101 |
1 files changed, 38 insertions, 63 deletions
diff --git a/fs/splice.c b/fs/splice.c index 2fca6ebf4cc2..badc78ff1246 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -576,76 +576,51 @@ static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, | |||
576 | if (this_len + offset > PAGE_CACHE_SIZE) | 576 | if (this_len + offset > PAGE_CACHE_SIZE) |
577 | this_len = PAGE_CACHE_SIZE - offset; | 577 | this_len = PAGE_CACHE_SIZE - offset; |
578 | 578 | ||
579 | /* | 579 | find_page: |
580 | * Reuse buf page, if SPLICE_F_MOVE is set and we are doing a full | 580 | page = find_lock_page(mapping, index); |
581 | * page. | 581 | if (!page) { |
582 | */ | 582 | ret = -ENOMEM; |
583 | if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { | 583 | page = page_cache_alloc_cold(mapping); |
584 | if (unlikely(!page)) | ||
585 | goto out_ret; | ||
586 | |||
584 | /* | 587 | /* |
585 | * If steal succeeds, buf->page is now pruned from the | 588 | * This will also lock the page |
586 | * pagecache and we can reuse it. The page will also be | ||
587 | * locked on successful return. | ||
588 | */ | 589 | */ |
589 | if (buf->ops->steal(pipe, buf)) | 590 | ret = add_to_page_cache_lru(page, mapping, index, |
590 | goto find_page; | 591 | GFP_KERNEL); |
591 | 592 | if (unlikely(ret)) | |
592 | page = buf->page; | 593 | goto out; |
593 | if (add_to_page_cache(page, mapping, index, GFP_KERNEL)) { | 594 | } |
594 | unlock_page(page); | ||
595 | goto find_page; | ||
596 | } | ||
597 | |||
598 | page_cache_get(page); | ||
599 | |||
600 | if (!(buf->flags & PIPE_BUF_FLAG_LRU)) | ||
601 | lru_cache_add(page); | ||
602 | } else { | ||
603 | find_page: | ||
604 | page = find_lock_page(mapping, index); | ||
605 | if (!page) { | ||
606 | ret = -ENOMEM; | ||
607 | page = page_cache_alloc_cold(mapping); | ||
608 | if (unlikely(!page)) | ||
609 | goto out_ret; | ||
610 | 595 | ||
611 | /* | 596 | /* |
612 | * This will also lock the page | 597 | * We get here with the page locked. If the page is also |
613 | */ | 598 | * uptodate, we don't need to do more. If it isn't, we |
614 | ret = add_to_page_cache_lru(page, mapping, index, | 599 | * may need to bring it in if we are not going to overwrite |
615 | GFP_KERNEL); | 600 | * the full page. |
601 | */ | ||
602 | if (!PageUptodate(page)) { | ||
603 | if (this_len < PAGE_CACHE_SIZE) { | ||
604 | ret = mapping->a_ops->readpage(file, page); | ||
616 | if (unlikely(ret)) | 605 | if (unlikely(ret)) |
617 | goto out; | 606 | goto out; |
618 | } | ||
619 | 607 | ||
620 | /* | 608 | lock_page(page); |
621 | * We get here with the page locked. If the page is also | 609 | |
622 | * uptodate, we don't need to do more. If it isn't, we | 610 | if (!PageUptodate(page)) { |
623 | * may need to bring it in if we are not going to overwrite | 611 | /* |
624 | * the full page. | 612 | * Page got invalidated, repeat. |
625 | */ | 613 | */ |
626 | if (!PageUptodate(page)) { | 614 | if (!page->mapping) { |
627 | if (this_len < PAGE_CACHE_SIZE) { | 615 | unlock_page(page); |
628 | ret = mapping->a_ops->readpage(file, page); | 616 | page_cache_release(page); |
629 | if (unlikely(ret)) | 617 | goto find_page; |
630 | goto out; | ||
631 | |||
632 | lock_page(page); | ||
633 | |||
634 | if (!PageUptodate(page)) { | ||
635 | /* | ||
636 | * Page got invalidated, repeat. | ||
637 | */ | ||
638 | if (!page->mapping) { | ||
639 | unlock_page(page); | ||
640 | page_cache_release(page); | ||
641 | goto find_page; | ||
642 | } | ||
643 | ret = -EIO; | ||
644 | goto out; | ||
645 | } | 618 | } |
646 | } else | 619 | ret = -EIO; |
647 | SetPageUptodate(page); | 620 | goto out; |
648 | } | 621 | } |
622 | } else | ||
623 | SetPageUptodate(page); | ||
649 | } | 624 | } |
650 | 625 | ||
651 | ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); | 626 | ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); |