diff options
-rw-r--r-- | fs/pipe.c | 3 | ||||
-rw-r--r-- | fs/splice.c | 30 | ||||
-rw-r--r-- | include/linux/pipe_fs_i.h | 4 |
3 files changed, 18 insertions, 19 deletions
@@ -95,6 +95,8 @@ static void anon_pipe_buf_release(struct pipe_inode_info *info, struct pipe_buff | |||
95 | { | 95 | { |
96 | struct page *page = buf->page; | 96 | struct page *page = buf->page; |
97 | 97 | ||
98 | buf->flags &= ~PIPE_BUF_FLAG_STOLEN; | ||
99 | |||
98 | /* | 100 | /* |
99 | * If nobody else uses this page, and we don't already have a | 101 | * If nobody else uses this page, and we don't already have a |
100 | * temporary page, let's keep track of it as a one-deep | 102 | * temporary page, let's keep track of it as a one-deep |
@@ -124,6 +126,7 @@ static void anon_pipe_buf_unmap(struct pipe_inode_info *info, struct pipe_buffer | |||
124 | static int anon_pipe_buf_steal(struct pipe_inode_info *info, | 126 | static int anon_pipe_buf_steal(struct pipe_inode_info *info, |
125 | struct pipe_buffer *buf) | 127 | struct pipe_buffer *buf) |
126 | { | 128 | { |
129 | buf->flags |= PIPE_BUF_FLAG_STOLEN; | ||
127 | return 0; | 130 | return 0; |
128 | } | 131 | } |
129 | 132 | ||
diff --git a/fs/splice.c b/fs/splice.c index b5fb2f3e3ac6..bfa42a277bb8 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -67,16 +67,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info, | |||
67 | if (!remove_mapping(mapping, page)) | 67 | if (!remove_mapping(mapping, page)) |
68 | return 1; | 68 | return 1; |
69 | 69 | ||
70 | if (PageLRU(page)) { | 70 | buf->flags |= PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU; |
71 | struct zone *zone = page_zone(page); | ||
72 | |||
73 | spin_lock_irq(&zone->lru_lock); | ||
74 | BUG_ON(!PageLRU(page)); | ||
75 | __ClearPageLRU(page); | ||
76 | del_page_from_lru(zone, page); | ||
77 | spin_unlock_irq(&zone->lru_lock); | ||
78 | } | ||
79 | |||
80 | return 0; | 71 | return 0; |
81 | } | 72 | } |
82 | 73 | ||
@@ -85,6 +76,7 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info, | |||
85 | { | 76 | { |
86 | page_cache_release(buf->page); | 77 | page_cache_release(buf->page); |
87 | buf->page = NULL; | 78 | buf->page = NULL; |
79 | buf->flags &= ~(PIPE_BUF_FLAG_STOLEN | PIPE_BUF_FLAG_LRU); | ||
88 | } | 80 | } |
89 | 81 | ||
90 | static void *page_cache_pipe_buf_map(struct file *file, | 82 | static void *page_cache_pipe_buf_map(struct file *file, |
@@ -414,11 +406,12 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
414 | { | 406 | { |
415 | struct file *file = sd->file; | 407 | struct file *file = sd->file; |
416 | struct address_space *mapping = file->f_mapping; | 408 | struct address_space *mapping = file->f_mapping; |
409 | gfp_t gfp_mask = mapping_gfp_mask(mapping); | ||
417 | unsigned int offset; | 410 | unsigned int offset; |
418 | struct page *page; | 411 | struct page *page; |
419 | pgoff_t index; | 412 | pgoff_t index; |
420 | char *src; | 413 | char *src; |
421 | int ret, stolen; | 414 | int ret; |
422 | 415 | ||
423 | /* | 416 | /* |
424 | * after this, page will be locked and unmapped | 417 | * after this, page will be locked and unmapped |
@@ -429,7 +422,6 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
429 | 422 | ||
430 | index = sd->pos >> PAGE_CACHE_SHIFT; | 423 | index = sd->pos >> PAGE_CACHE_SHIFT; |
431 | offset = sd->pos & ~PAGE_CACHE_MASK; | 424 | offset = sd->pos & ~PAGE_CACHE_MASK; |
432 | stolen = 0; | ||
433 | 425 | ||
434 | /* | 426 | /* |
435 | * reuse buf page, if SPLICE_F_MOVE is set | 427 | * reuse buf page, if SPLICE_F_MOVE is set |
@@ -443,15 +435,15 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
443 | goto find_page; | 435 | goto find_page; |
444 | 436 | ||
445 | page = buf->page; | 437 | page = buf->page; |
446 | stolen = 1; | 438 | if (add_to_page_cache(page, mapping, index, gfp_mask)) |
447 | if (add_to_page_cache_lru(page, mapping, index, | ||
448 | mapping_gfp_mask(mapping))) | ||
449 | goto find_page; | 439 | goto find_page; |
440 | |||
441 | if (!(buf->flags & PIPE_BUF_FLAG_LRU)) | ||
442 | lru_cache_add(page); | ||
450 | } else { | 443 | } else { |
451 | find_page: | 444 | find_page: |
452 | ret = -ENOMEM; | 445 | ret = -ENOMEM; |
453 | page = find_or_create_page(mapping, index, | 446 | page = find_or_create_page(mapping, index, gfp_mask); |
454 | mapping_gfp_mask(mapping)); | ||
455 | if (!page) | 447 | if (!page) |
456 | goto out; | 448 | goto out; |
457 | 449 | ||
@@ -494,7 +486,7 @@ find_page: | |||
494 | } else if (ret) | 486 | } else if (ret) |
495 | goto out; | 487 | goto out; |
496 | 488 | ||
497 | if (!stolen) { | 489 | if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) { |
498 | char *dst = kmap_atomic(page, KM_USER0); | 490 | char *dst = kmap_atomic(page, KM_USER0); |
499 | 491 | ||
500 | memcpy(dst + offset, src + buf->offset, sd->len); | 492 | memcpy(dst + offset, src + buf->offset, sd->len); |
@@ -511,7 +503,7 @@ find_page: | |||
511 | 503 | ||
512 | balance_dirty_pages_ratelimited(mapping); | 504 | balance_dirty_pages_ratelimited(mapping); |
513 | out: | 505 | out: |
514 | if (!stolen) { | 506 | if (!(buf->flags & PIPE_BUF_FLAG_STOLEN)) { |
515 | page_cache_release(page); | 507 | page_cache_release(page); |
516 | unlock_page(page); | 508 | unlock_page(page); |
517 | } | 509 | } |
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 70ae9332ec16..ec384958d509 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h | |||
@@ -5,10 +5,14 @@ | |||
5 | 5 | ||
6 | #define PIPE_BUFFERS (16) | 6 | #define PIPE_BUFFERS (16) |
7 | 7 | ||
8 | #define PIPE_BUF_FLAG_STOLEN 0x01 | ||
9 | #define PIPE_BUF_FLAG_LRU 0x02 | ||
10 | |||
8 | struct pipe_buffer { | 11 | struct pipe_buffer { |
9 | struct page *page; | 12 | struct page *page; |
10 | unsigned int offset, len; | 13 | unsigned int offset, len; |
11 | struct pipe_buf_operations *ops; | 14 | struct pipe_buf_operations *ops; |
15 | unsigned int flags; | ||
12 | }; | 16 | }; |
13 | 17 | ||
14 | struct pipe_buf_operations { | 18 | struct pipe_buf_operations { |