diff options
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 40 |
1 files changed, 30 insertions, 10 deletions
diff --git a/fs/splice.c b/fs/splice.c index 8b5efcc906dc..50c43a1e0923 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -84,26 +84,43 @@ static void *page_cache_pipe_buf_map(struct file *file, | |||
84 | struct pipe_buffer *buf) | 84 | struct pipe_buffer *buf) |
85 | { | 85 | { |
86 | struct page *page = buf->page; | 86 | struct page *page = buf->page; |
87 | 87 | int err; | |
88 | lock_page(page); | ||
89 | 88 | ||
90 | if (!PageUptodate(page)) { | 89 | if (!PageUptodate(page)) { |
91 | unlock_page(page); | 90 | lock_page(page); |
92 | return ERR_PTR(-EIO); | 91 | |
93 | } | 92 | /* |
93 | * Page got truncated/unhashed. This will cause a 0-byte | ||
94 | * splice, if this is the first page | ||
95 | */ | ||
96 | if (!page->mapping) { | ||
97 | err = -ENODATA; | ||
98 | goto error; | ||
99 | } | ||
100 | |||
101 | /* | ||
102 | * uh oh, read-error from disk | ||
103 | */ | ||
104 | if (!PageUptodate(page)) { | ||
105 | err = -EIO; | ||
106 | goto error; | ||
107 | } | ||
94 | 108 | ||
95 | if (!page->mapping) { | 109 | /* |
110 | * page is ok afterall, fall through to mapping | ||
111 | */ | ||
96 | unlock_page(page); | 112 | unlock_page(page); |
97 | return ERR_PTR(-ENODATA); | ||
98 | } | 113 | } |
99 | 114 | ||
100 | return kmap(buf->page); | 115 | return kmap(page); |
116 | error: | ||
117 | unlock_page(page); | ||
118 | return ERR_PTR(err); | ||
101 | } | 119 | } |
102 | 120 | ||
103 | static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, | 121 | static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, |
104 | struct pipe_buffer *buf) | 122 | struct pipe_buffer *buf) |
105 | { | 123 | { |
106 | unlock_page(buf->page); | ||
107 | kunmap(buf->page); | 124 | kunmap(buf->page); |
108 | } | 125 | } |
109 | 126 | ||
@@ -379,7 +396,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
379 | int ret; | 396 | int ret; |
380 | 397 | ||
381 | /* | 398 | /* |
382 | * after this, page will be locked and unmapped | 399 | * make sure the data in this buffer is uptodate |
383 | */ | 400 | */ |
384 | src = buf->ops->map(file, info, buf); | 401 | src = buf->ops->map(file, info, buf); |
385 | if (IS_ERR(src)) | 402 | if (IS_ERR(src)) |
@@ -399,6 +416,9 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf, | |||
399 | if (buf->ops->steal(info, buf)) | 416 | if (buf->ops->steal(info, buf)) |
400 | goto find_page; | 417 | goto find_page; |
401 | 418 | ||
419 | /* | ||
420 | * this will also set the page locked | ||
421 | */ | ||
402 | page = buf->page; | 422 | page = buf->page; |
403 | if (add_to_page_cache(page, mapping, index, gfp_mask)) | 423 | if (add_to_page_cache(page, mapping, index, gfp_mask)) |
404 | goto find_page; | 424 | goto find_page; |