diff options
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 74 |
1 files changed, 39 insertions, 35 deletions
diff --git a/fs/splice.c b/fs/splice.c index 7fb04970c72d..a285fd746dc0 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -51,7 +51,7 @@ struct splice_pipe_desc { | |||
51 | * addition of remove_mapping(). If success is returned, the caller may | 51 | * addition of remove_mapping(). If success is returned, the caller may |
52 | * attempt to reuse this page for another destination. | 52 | * attempt to reuse this page for another destination. |
53 | */ | 53 | */ |
54 | static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, | 54 | static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe, |
55 | struct pipe_buffer *buf) | 55 | struct pipe_buffer *buf) |
56 | { | 56 | { |
57 | struct page *page = buf->page; | 57 | struct page *page = buf->page; |
@@ -78,16 +78,18 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, | |||
78 | return 1; | 78 | return 1; |
79 | } | 79 | } |
80 | 80 | ||
81 | buf->flags |= PIPE_BUF_FLAG_LRU; | ||
81 | return 0; | 82 | return 0; |
82 | } | 83 | } |
83 | 84 | ||
84 | static void page_cache_pipe_buf_release(struct pipe_inode_info *info, | 85 | static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, |
85 | struct pipe_buffer *buf) | 86 | struct pipe_buffer *buf) |
86 | { | 87 | { |
87 | page_cache_release(buf->page); | 88 | page_cache_release(buf->page); |
89 | buf->flags &= ~PIPE_BUF_FLAG_LRU; | ||
88 | } | 90 | } |
89 | 91 | ||
90 | static int page_cache_pipe_buf_pin(struct pipe_inode_info *info, | 92 | static int page_cache_pipe_buf_pin(struct pipe_inode_info *pipe, |
91 | struct pipe_buffer *buf) | 93 | struct pipe_buffer *buf) |
92 | { | 94 | { |
93 | struct page *page = buf->page; | 95 | struct page *page = buf->page; |
@@ -141,6 +143,7 @@ static int user_page_pipe_buf_steal(struct pipe_inode_info *pipe, | |||
141 | if (!(buf->flags & PIPE_BUF_FLAG_GIFT)) | 143 | if (!(buf->flags & PIPE_BUF_FLAG_GIFT)) |
142 | return 1; | 144 | return 1; |
143 | 145 | ||
146 | buf->flags |= PIPE_BUF_FLAG_LRU; | ||
144 | return generic_pipe_buf_steal(pipe, buf); | 147 | return generic_pipe_buf_steal(pipe, buf); |
145 | } | 148 | } |
146 | 149 | ||
@@ -321,6 +324,8 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
321 | mapping_gfp_mask(mapping)); | 324 | mapping_gfp_mask(mapping)); |
322 | if (unlikely(error)) { | 325 | if (unlikely(error)) { |
323 | page_cache_release(page); | 326 | page_cache_release(page); |
327 | if (error == -EEXIST) | ||
328 | continue; | ||
324 | break; | 329 | break; |
325 | } | 330 | } |
326 | /* | 331 | /* |
@@ -497,14 +502,14 @@ EXPORT_SYMBOL(generic_file_splice_read); | |||
497 | * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' | 502 | * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' |
498 | * using sendpage(). Return the number of bytes sent. | 503 | * using sendpage(). Return the number of bytes sent. |
499 | */ | 504 | */ |
500 | static int pipe_to_sendpage(struct pipe_inode_info *info, | 505 | static int pipe_to_sendpage(struct pipe_inode_info *pipe, |
501 | struct pipe_buffer *buf, struct splice_desc *sd) | 506 | struct pipe_buffer *buf, struct splice_desc *sd) |
502 | { | 507 | { |
503 | struct file *file = sd->file; | 508 | struct file *file = sd->file; |
504 | loff_t pos = sd->pos; | 509 | loff_t pos = sd->pos; |
505 | int ret, more; | 510 | int ret, more; |
506 | 511 | ||
507 | ret = buf->ops->pin(info, buf); | 512 | ret = buf->ops->pin(pipe, buf); |
508 | if (!ret) { | 513 | if (!ret) { |
509 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; | 514 | more = (sd->flags & SPLICE_F_MORE) || sd->len < sd->total_len; |
510 | 515 | ||
@@ -535,7 +540,7 @@ static int pipe_to_sendpage(struct pipe_inode_info *info, | |||
535 | * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create | 540 | * SPLICE_F_MOVE isn't set, or we cannot move the page, we simply create |
536 | * a new page in the output file page cache and fill/dirty that. | 541 | * a new page in the output file page cache and fill/dirty that. |
537 | */ | 542 | */ |
538 | static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | 543 | static int pipe_to_file(struct pipe_inode_info *pipe, struct pipe_buffer *buf, |
539 | struct splice_desc *sd) | 544 | struct splice_desc *sd) |
540 | { | 545 | { |
541 | struct file *file = sd->file; | 546 | struct file *file = sd->file; |
@@ -549,7 +554,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
549 | /* | 554 | /* |
550 | * make sure the data in this buffer is uptodate | 555 | * make sure the data in this buffer is uptodate |
551 | */ | 556 | */ |
552 | ret = buf->ops->pin(info, buf); | 557 | ret = buf->ops->pin(pipe, buf); |
553 | if (unlikely(ret)) | 558 | if (unlikely(ret)) |
554 | return ret; | 559 | return ret; |
555 | 560 | ||
@@ -566,37 +571,23 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
566 | */ | 571 | */ |
567 | if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { | 572 | if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { |
568 | /* | 573 | /* |
569 | * If steal succeeds, buf->page is now pruned from the vm | 574 | * If steal succeeds, buf->page is now pruned from the |
570 | * side (page cache) and we can reuse it. The page will also | 575 | * pagecache and we can reuse it. The page will also be |
571 | * be locked on successful return. | 576 | * locked on successful return. |
572 | */ | 577 | */ |
573 | if (buf->ops->steal(info, buf)) | 578 | if (buf->ops->steal(pipe, buf)) |
574 | goto find_page; | 579 | goto find_page; |
575 | 580 | ||
576 | page = buf->page; | 581 | page = buf->page; |
577 | page_cache_get(page); | ||
578 | |||
579 | /* | ||
580 | * page must be on the LRU for adding to the pagecache. | ||
581 | * Check this without grabbing the zone lock, if it isn't | ||
582 | * the do grab the zone lock, recheck, and add if necessary. | ||
583 | */ | ||
584 | if (!PageLRU(page)) { | ||
585 | struct zone *zone = page_zone(page); | ||
586 | |||
587 | spin_lock_irq(&zone->lru_lock); | ||
588 | if (!PageLRU(page)) { | ||
589 | SetPageLRU(page); | ||
590 | add_page_to_inactive_list(zone, page); | ||
591 | } | ||
592 | spin_unlock_irq(&zone->lru_lock); | ||
593 | } | ||
594 | |||
595 | if (add_to_page_cache(page, mapping, index, gfp_mask)) { | 582 | if (add_to_page_cache(page, mapping, index, gfp_mask)) { |
596 | page_cache_release(page); | ||
597 | unlock_page(page); | 583 | unlock_page(page); |
598 | goto find_page; | 584 | goto find_page; |
599 | } | 585 | } |
586 | |||
587 | page_cache_get(page); | ||
588 | |||
589 | if (!(buf->flags & PIPE_BUF_FLAG_LRU)) | ||
590 | lru_cache_add(page); | ||
600 | } else { | 591 | } else { |
601 | find_page: | 592 | find_page: |
602 | page = find_lock_page(mapping, index); | 593 | page = find_lock_page(mapping, index); |
@@ -647,23 +638,36 @@ find_page: | |||
647 | } | 638 | } |
648 | 639 | ||
649 | ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); | 640 | ret = mapping->a_ops->prepare_write(file, page, offset, offset+this_len); |
650 | if (ret == AOP_TRUNCATED_PAGE) { | 641 | if (unlikely(ret)) { |
642 | loff_t isize = i_size_read(mapping->host); | ||
643 | |||
644 | if (ret != AOP_TRUNCATED_PAGE) | ||
645 | unlock_page(page); | ||
651 | page_cache_release(page); | 646 | page_cache_release(page); |
652 | goto find_page; | 647 | if (ret == AOP_TRUNCATED_PAGE) |
653 | } else if (ret) | 648 | goto find_page; |
649 | |||
650 | /* | ||
651 | * prepare_write() may have instantiated a few blocks | ||
652 | * outside i_size. Trim these off again. | ||
653 | */ | ||
654 | if (sd->pos + this_len > isize) | ||
655 | vmtruncate(mapping->host, isize); | ||
656 | |||
654 | goto out; | 657 | goto out; |
658 | } | ||
655 | 659 | ||
656 | if (buf->page != page) { | 660 | if (buf->page != page) { |
657 | /* | 661 | /* |
658 | * Careful, ->map() uses KM_USER0! | 662 | * Careful, ->map() uses KM_USER0! |
659 | */ | 663 | */ |
660 | char *src = buf->ops->map(info, buf, 1); | 664 | char *src = buf->ops->map(pipe, buf, 1); |
661 | char *dst = kmap_atomic(page, KM_USER1); | 665 | char *dst = kmap_atomic(page, KM_USER1); |
662 | 666 | ||
663 | memcpy(dst + offset, src + buf->offset, this_len); | 667 | memcpy(dst + offset, src + buf->offset, this_len); |
664 | flush_dcache_page(page); | 668 | flush_dcache_page(page); |
665 | kunmap_atomic(dst, KM_USER1); | 669 | kunmap_atomic(dst, KM_USER1); |
666 | buf->ops->unmap(info, buf, src); | 670 | buf->ops->unmap(pipe, buf, src); |
667 | } | 671 | } |
668 | 672 | ||
669 | ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); | 673 | ret = mapping->a_ops->commit_write(file, page, offset, offset+this_len); |