summaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-05-02 15:03:27 +0200
committerJens Axboe <axboe@suse.de>2006-05-02 15:03:27 +0200
commita893b99be71f1d669b74f840e3a683dd077d007b (patch)
tree79591f70b57ef4504dc5c9584b7d8fcaa04faede /fs/splice.c
parent7591489a8fbee83f19bacc75756989a6a4d0389c (diff)
downloadlinux-a893b99be71f1d669b74f840e3a683dd077d007b.tar.gz
linux-a893b99be71f1d669b74f840e3a683dd077d007b.tar.bz2
linux-a893b99be71f1d669b74f840e3a683dd077d007b.zip
[PATCH] splice: fix page LRU accounting
Currently we rely on the PIPE_BUF_FLAG_LRU flag being set correctly to know whether we need to fiddle with page LRU state after stealing it, however for some origins we just don't know if the page is on the LRU list or not. So remove PIPE_BUF_FLAG_LRU and do this check/add manually in pipe_to_file() instead. Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c31
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,
return 1;
}
- buf->flags |= PIPE_BUF_FLAG_LRU;
return 0;
}
@@ -86,8 +85,6 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info,
struct pipe_buffer *buf)
{
page_cache_release(buf->page);
- buf->page = NULL;
- buf->flags &= ~PIPE_BUF_FLAG_LRU;
}
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,
if ((sd->flags & SPLICE_F_MOVE) && this_len == PAGE_CACHE_SIZE) {
/*
* If steal succeeds, buf->page is now pruned from the vm
- * side (LRU and page cache) and we can reuse it. The page
- * will also be looked on successful return.
+ * side (page cache) and we can reuse it. The page will also
+ * be locked on successful return.
*/
if (buf->ops->steal(info, buf))
goto find_page;
page = buf->page;
+ page_cache_get(page);
+
+ /*
+ * page must be on the LRU for adding to the pagecache.
+ * Check this without grabbing the zone lock, if it isn't
+ * the do grab the zone lock, recheck, and add if necessary.
+ */
+ if (!PageLRU(page)) {
+ struct zone *zone = page_zone(page);
+
+ spin_lock_irq(&zone->lru_lock);
+ if (!PageLRU(page)) {
+ SetPageLRU(page);
+ add_page_to_inactive_list(zone, page);
+ }
+ spin_unlock_irq(&zone->lru_lock);
+ }
+
if (add_to_page_cache(page, mapping, index, gfp_mask)) {
+ page_cache_release(page);
unlock_page(page);
goto find_page;
}
-
- page_cache_get(page);
-
- if (!(buf->flags & PIPE_BUF_FLAG_LRU))
- lru_cache_add(page);
} else {
find_page:
page = find_lock_page(mapping, index);