aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/splice.c40
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);
116error:
117 unlock_page(page);
118 return ERR_PTR(err);
101} 119}
102 120
103static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, 121static 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;