diff options
Diffstat (limited to 'fs/splice.c')
| -rw-r--r-- | fs/splice.c | 46 |
1 files changed, 29 insertions, 17 deletions
diff --git a/fs/splice.c b/fs/splice.c index a285fd746dc0..05fd2787be98 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -55,31 +55,43 @@ 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; |
| 58 | struct address_space *mapping = page_mapping(page); | 58 | struct address_space *mapping; |
| 59 | 59 | ||
| 60 | lock_page(page); | 60 | lock_page(page); |
| 61 | 61 | ||
| 62 | WARN_ON(!PageUptodate(page)); | 62 | mapping = page_mapping(page); |
| 63 | if (mapping) { | ||
| 64 | WARN_ON(!PageUptodate(page)); | ||
| 63 | 65 | ||
| 64 | /* | 66 | /* |
| 65 | * At least for ext2 with nobh option, we need to wait on writeback | 67 | * At least for ext2 with nobh option, we need to wait on |
| 66 | * completing on this page, since we'll remove it from the pagecache. | 68 | * writeback completing on this page, since we'll remove it |
| 67 | * Otherwise truncate wont wait on the page, allowing the disk | 69 | * from the pagecache. Otherwise truncate wont wait on the |
| 68 | * blocks to be reused by someone else before we actually wrote our | 70 | * page, allowing the disk blocks to be reused by someone else |
| 69 | * data to them. fs corruption ensues. | 71 | * before we actually wrote our data to them. fs corruption |
| 70 | */ | 72 | * ensues. |
| 71 | wait_on_page_writeback(page); | 73 | */ |
| 74 | wait_on_page_writeback(page); | ||
| 72 | 75 | ||
| 73 | if (PagePrivate(page)) | 76 | if (PagePrivate(page)) |
| 74 | try_to_release_page(page, mapping_gfp_mask(mapping)); | 77 | try_to_release_page(page, mapping_gfp_mask(mapping)); |
| 75 | 78 | ||
| 76 | if (!remove_mapping(mapping, page)) { | 79 | /* |
| 77 | unlock_page(page); | 80 | * If we succeeded in removing the mapping, set LRU flag |
| 78 | return 1; | 81 | * and return good. |
| 82 | */ | ||
| 83 | if (remove_mapping(mapping, page)) { | ||
| 84 | buf->flags |= PIPE_BUF_FLAG_LRU; | ||
| 85 | return 0; | ||
| 86 | } | ||
| 79 | } | 87 | } |
| 80 | 88 | ||
| 81 | buf->flags |= PIPE_BUF_FLAG_LRU; | 89 | /* |
| 82 | return 0; | 90 | * Raced with truncate or failed to remove page from current |
| 91 | * address space, unlock and return failure. | ||
| 92 | */ | ||
| 93 | unlock_page(page); | ||
| 94 | return 1; | ||
| 83 | } | 95 | } |
| 84 | 96 | ||
| 85 | static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, | 97 | static void page_cache_pipe_buf_release(struct pipe_inode_info *pipe, |
