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 { |
