diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/fs/splice.c b/fs/splice.c index b0c157d76948..3318b965c10b 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -78,7 +78,6 @@ 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; | ||
82 | return 0; | 81 | return 0; |
83 | } | 82 | } |
84 | 83 | ||
@@ -86,8 +85,6 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info, | |||
86 | struct pipe_buffer *buf) | 85 | struct pipe_buffer *buf) |
87 | { | 86 | { |
88 | page_cache_release(buf->page); | 87 | page_cache_release(buf->page); |
89 | buf->page = NULL; | ||
90 | buf->flags &= ~PIPE_BUF_FLAG_LRU; | ||
91 | } | 88 | } |
92 | 89 | ||
93 | static int page_cache_pipe_buf_pin(struct pipe_inode_info *info, | 90 | static int page_cache_pipe_buf_pin(struct pipe_inode_info *info, |
@@ -570,22 +567,36 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
570 | if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { | 567 | if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) { |
571 | /* | 568 | /* |
572 | * If steal succeeds, buf->page is now pruned from the vm | 569 | * If steal succeeds, buf->page is now pruned from the vm |
573 | * side (LRU and page cache) and we can reuse it. The page | 570 | * side (page cache) and we can reuse it. The page will also |
574 | * will also be looked on successful return. | 571 | * be locked on successful return. |
575 | */ | 572 | */ |
576 | if (buf->ops->steal(info, buf)) | 573 | if (buf->ops->steal(info, buf)) |
577 | goto find_page; | 574 | goto find_page; |
578 | 575 | ||
579 | page = buf->page; | 576 | 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 | |||
580 | if (add_to_page_cache(page, mapping, index, gfp_mask)) { | 595 | if (add_to_page_cache(page, mapping, index, gfp_mask)) { |
596 | page_cache_release(page); | ||
581 | unlock_page(page); | 597 | unlock_page(page); |
582 | goto find_page; | 598 | goto find_page; |
583 | } | 599 | } |
584 | |||
585 | page_cache_get(page); | ||
586 | |||
587 | if (!(buf->flags & PIPE_BUF_FLAG_LRU)) | ||
588 | lru_cache_add(page); | ||
589 | } else { | 600 | } else { |
590 | find_page: | 601 | find_page: |
591 | page = find_lock_page(mapping, index); | 602 | page = find_lock_page(mapping, index); |