diff options
| -rw-r--r-- | fs/compat.c | 2 | ||||
| -rw-r--r-- | fs/splice.c | 74 | ||||
| -rw-r--r-- | include/linux/pipe_fs_i.h | 5 |
3 files changed, 43 insertions, 38 deletions
diff --git a/fs/compat.c b/fs/compat.c index 3f3e8f4d43d6..970888aad843 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -1323,7 +1323,7 @@ compat_sys_vmsplice(int fd, const struct compat_iovec __user *iov32, | |||
| 1323 | { | 1323 | { |
| 1324 | unsigned i; | 1324 | unsigned i; |
| 1325 | struct iovec *iov; | 1325 | struct iovec *iov; |
| 1326 | if (nr_segs >= UIO_MAXIOV) | 1326 | if (nr_segs > UIO_MAXIOV) |
| 1327 | return -EINVAL; | 1327 | return -EINVAL; |
| 1328 | iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); | 1328 | iov = compat_alloc_user_space(nr_segs * sizeof(struct iovec)); |
| 1329 | for (i = 0; i < nr_segs; i++) { | 1329 | for (i = 0; i < nr_segs; i++) { |
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); |
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index ba73108cbf8b..ea4f7cd7bfd8 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h | |||
| @@ -5,8 +5,9 @@ | |||
| 5 | 5 | ||
| 6 | #define PIPE_BUFFERS (16) | 6 | #define PIPE_BUFFERS (16) |
| 7 | 7 | ||
| 8 | #define PIPE_BUF_FLAG_ATOMIC 0x01 /* was atomically mapped */ | 8 | #define PIPE_BUF_FLAG_LRU 0x01 /* page is on the LRU */ |
| 9 | #define PIPE_BUF_FLAG_GIFT 0x02 /* page is a gift */ | 9 | #define PIPE_BUF_FLAG_ATOMIC 0x02 /* was atomically mapped */ |
| 10 | #define PIPE_BUF_FLAG_GIFT 0x04 /* page is a gift */ | ||
| 10 | 11 | ||
| 11 | struct pipe_buffer { | 12 | struct pipe_buffer { |
| 12 | struct page *page; | 13 | struct page *page; |
