diff options
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 59 |
1 files changed, 10 insertions, 49 deletions
diff --git a/fs/splice.c b/fs/splice.c index 9f796b1034d1..8b5efcc906dc 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -220,10 +220,10 @@ static int __generic_file_splice_read(struct file *in, struct inode *pipe, | |||
220 | { | 220 | { |
221 | struct address_space *mapping = in->f_mapping; | 221 | struct address_space *mapping = in->f_mapping; |
222 | unsigned int offset, nr_pages; | 222 | unsigned int offset, nr_pages; |
223 | struct page *pages[PIPE_BUFFERS], *shadow[PIPE_BUFFERS]; | 223 | struct page *pages[PIPE_BUFFERS]; |
224 | struct page *page; | 224 | struct page *page; |
225 | pgoff_t index, pidx; | 225 | pgoff_t index; |
226 | int i, j; | 226 | int i; |
227 | 227 | ||
228 | index = in->f_pos >> PAGE_CACHE_SHIFT; | 228 | index = in->f_pos >> PAGE_CACHE_SHIFT; |
229 | offset = in->f_pos & ~PAGE_CACHE_MASK; | 229 | offset = in->f_pos & ~PAGE_CACHE_MASK; |
@@ -238,41 +238,13 @@ static int __generic_file_splice_read(struct file *in, struct inode *pipe, | |||
238 | do_page_cache_readahead(mapping, in, index, nr_pages); | 238 | do_page_cache_readahead(mapping, in, index, nr_pages); |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Get as many pages from the page cache as possible.. | ||
242 | * Start IO on the page cache entries we create (we | ||
243 | * can assume that any pre-existing ones we find have | ||
244 | * already had IO started on them). | ||
245 | */ | ||
246 | i = find_get_pages(mapping, index, nr_pages, pages); | ||
247 | |||
248 | /* | ||
249 | * common case - we found all pages and they are contiguous, | ||
250 | * kick them off | ||
251 | */ | ||
252 | if (i && (pages[i - 1]->index == index + i - 1)) | ||
253 | goto splice_them; | ||
254 | |||
255 | /* | ||
256 | * fill shadow[] with pages at the right locations, so we only | ||
257 | * have to fill holes | ||
258 | */ | ||
259 | memset(shadow, 0, nr_pages * sizeof(struct page *)); | ||
260 | for (j = 0; j < i; j++) | ||
261 | shadow[pages[j]->index - index] = pages[j]; | ||
262 | |||
263 | /* | ||
264 | * now fill in the holes | 241 | * now fill in the holes |
265 | */ | 242 | */ |
266 | for (i = 0, pidx = index; i < nr_pages; pidx++, i++) { | 243 | for (i = 0; i < nr_pages; i++, index++) { |
267 | int error; | ||
268 | |||
269 | if (shadow[i]) | ||
270 | continue; | ||
271 | |||
272 | /* | 244 | /* |
273 | * no page there, look one up / create it | 245 | * no page there, look one up / create it |
274 | */ | 246 | */ |
275 | page = find_or_create_page(mapping, pidx, | 247 | page = find_or_create_page(mapping, index, |
276 | mapping_gfp_mask(mapping)); | 248 | mapping_gfp_mask(mapping)); |
277 | if (!page) | 249 | if (!page) |
278 | break; | 250 | break; |
@@ -280,31 +252,20 @@ static int __generic_file_splice_read(struct file *in, struct inode *pipe, | |||
280 | if (PageUptodate(page)) | 252 | if (PageUptodate(page)) |
281 | unlock_page(page); | 253 | unlock_page(page); |
282 | else { | 254 | else { |
283 | error = mapping->a_ops->readpage(in, page); | 255 | int error = mapping->a_ops->readpage(in, page); |
284 | 256 | ||
285 | if (unlikely(error)) { | 257 | if (unlikely(error)) { |
286 | page_cache_release(page); | 258 | page_cache_release(page); |
287 | break; | 259 | break; |
288 | } | 260 | } |
289 | } | 261 | } |
290 | shadow[i] = page; | 262 | pages[i] = page; |
291 | } | ||
292 | |||
293 | if (!i) { | ||
294 | for (i = 0; i < nr_pages; i++) { | ||
295 | if (shadow[i]) | ||
296 | page_cache_release(shadow[i]); | ||
297 | } | ||
298 | return 0; | ||
299 | } | 263 | } |
300 | 264 | ||
301 | memcpy(pages, shadow, i * sizeof(struct page *)); | 265 | if (i) |
266 | return move_to_pipe(pipe, pages, i, offset, len, flags); | ||
302 | 267 | ||
303 | /* | 268 | return 0; |
304 | * Now we splice them into the pipe.. | ||
305 | */ | ||
306 | splice_them: | ||
307 | return move_to_pipe(pipe, pages, i, offset, len, flags); | ||
308 | } | 269 | } |
309 | 270 | ||
310 | /** | 271 | /** |