diff options
| author | Jens Axboe <axboe@suse.de> | 2006-04-19 09:55:10 -0400 |
|---|---|---|
| committer | Jens Axboe <axboe@suse.de> | 2006-04-19 09:55:10 -0400 |
| commit | 91ad66ef4469cb631ec0ccd131b07f16770773f7 (patch) | |
| tree | 89db609ce4d9673ad1f586abe87c76d6f38ab0d0 | |
| parent | 8bbde0e6d52265158ee9625f383500c1a7d09ba9 (diff) | |
[PATCH] splice: close i_size truncate races on read
We need to check i_size after doing a blocking readpage.
Signed-off-by: Jens Axboe <axboe@suse.de>
| -rw-r--r-- | fs/splice.c | 43 |
1 files changed, 37 insertions, 6 deletions
diff --git a/fs/splice.c b/fs/splice.c index 8d57e89924a6..7e8585574726 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -145,8 +145,8 @@ static struct pipe_buf_operations page_cache_pipe_buf_ops = { | |||
| 145 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). | 145 | * pipe buffer operations. Otherwise very similar to the regular pipe_writev(). |
| 146 | */ | 146 | */ |
| 147 | static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, | 147 | static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, |
| 148 | int nr_pages, unsigned long offset, | 148 | int nr_pages, unsigned long len, |
| 149 | unsigned long len, unsigned int flags) | 149 | unsigned int offset, unsigned int flags) |
| 150 | { | 150 | { |
| 151 | int ret, do_wakeup, i; | 151 | int ret, do_wakeup, i; |
| 152 | 152 | ||
| @@ -243,14 +243,16 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 243 | unsigned int flags) | 243 | unsigned int flags) |
| 244 | { | 244 | { |
| 245 | struct address_space *mapping = in->f_mapping; | 245 | struct address_space *mapping = in->f_mapping; |
| 246 | unsigned int offset, nr_pages; | 246 | unsigned int loff, offset, nr_pages; |
| 247 | struct page *pages[PIPE_BUFFERS]; | 247 | struct page *pages[PIPE_BUFFERS]; |
| 248 | struct page *page; | 248 | struct page *page; |
| 249 | pgoff_t index; | 249 | pgoff_t index, end_index; |
| 250 | loff_t isize; | ||
| 251 | size_t bytes; | ||
| 250 | int i, error; | 252 | int i, error; |
| 251 | 253 | ||
| 252 | index = *ppos >> PAGE_CACHE_SHIFT; | 254 | index = *ppos >> PAGE_CACHE_SHIFT; |
| 253 | offset = *ppos & ~PAGE_CACHE_MASK; | 255 | loff = offset = *ppos & ~PAGE_CACHE_MASK; |
| 254 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 256 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 255 | 257 | ||
| 256 | if (nr_pages > PIPE_BUFFERS) | 258 | if (nr_pages > PIPE_BUFFERS) |
| @@ -268,6 +270,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 268 | * Now fill in the holes: | 270 | * Now fill in the holes: |
| 269 | */ | 271 | */ |
| 270 | error = 0; | 272 | error = 0; |
| 273 | bytes = 0; | ||
| 271 | for (i = 0; i < nr_pages; i++, index++) { | 274 | for (i = 0; i < nr_pages; i++, index++) { |
| 272 | find_page: | 275 | find_page: |
| 273 | /* | 276 | /* |
| @@ -336,13 +339,41 @@ readpage: | |||
| 336 | goto find_page; | 339 | goto find_page; |
| 337 | break; | 340 | break; |
| 338 | } | 341 | } |
| 342 | |||
| 343 | /* | ||
| 344 | * i_size must be checked after ->readpage(). | ||
| 345 | */ | ||
| 346 | isize = i_size_read(mapping->host); | ||
| 347 | end_index = (isize - 1) >> PAGE_CACHE_SHIFT; | ||
| 348 | if (unlikely(!isize || index > end_index)) { | ||
| 349 | page_cache_release(page); | ||
| 350 | break; | ||
| 351 | } | ||
| 352 | |||
| 353 | /* | ||
| 354 | * if this is the last page, see if we need to shrink | ||
| 355 | * the length and stop | ||
| 356 | */ | ||
| 357 | if (end_index == index) { | ||
| 358 | loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); | ||
| 359 | if (bytes + loff > isize) { | ||
| 360 | page_cache_release(page); | ||
| 361 | break; | ||
| 362 | } | ||
| 363 | /* | ||
| 364 | * force quit after adding this page | ||
| 365 | */ | ||
| 366 | nr_pages = i; | ||
| 367 | } | ||
| 339 | } | 368 | } |
| 340 | fill_it: | 369 | fill_it: |
| 341 | pages[i] = page; | 370 | pages[i] = page; |
| 371 | bytes += PAGE_CACHE_SIZE - loff; | ||
| 372 | loff = 0; | ||
| 342 | } | 373 | } |
| 343 | 374 | ||
| 344 | if (i) | 375 | if (i) |
| 345 | return move_to_pipe(pipe, pages, i, offset, len, flags); | 376 | return move_to_pipe(pipe, pages, i, bytes, offset, flags); |
| 346 | 377 | ||
| 347 | return error; | 378 | return error; |
| 348 | } | 379 | } |
