diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-06-11 14:31:05 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-06-11 14:31:05 -0400 |
commit | 5212c555be332fc95982077e6cdc7bb6cb5fff5f (patch) | |
tree | 44907e3427949462dcc54ae762cc49ae8e9571f0 /fs | |
parent | 845a2fdcbd5bc5b9f652201ee95c825827a1d521 (diff) | |
parent | 620a324b744a7d66c3c45a83042f8e7fc9fc5a04 (diff) |
Merge branch 'splice-2.6.22' of git://git.kernel.dk/data/git/linux-2.6-block
* 'splice-2.6.22' of git://git.kernel.dk/data/git/linux-2.6-block:
splice: __generic_file_splice_read: fix read/truncate race
splice: __generic_file_splice_read: fix i_size_read() length checks
splice: move balance_dirty_pages_ratelimited() outside of splice actor
pipe: move pipe_inode_info structure decleration up before it's used
splice: remove do_splice_direct() symbol export
splice: move inode size check into generic_file_splice_read()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 70 |
1 files changed, 35 insertions, 35 deletions
diff --git a/fs/splice.c b/fs/splice.c index 12f28281d2b1..cb211360273a 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -272,7 +272,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
272 | struct page *page; | 272 | struct page *page; |
273 | pgoff_t index, end_index; | 273 | pgoff_t index, end_index; |
274 | loff_t isize; | 274 | loff_t isize; |
275 | size_t total_len; | ||
276 | int error, page_nr; | 275 | int error, page_nr; |
277 | struct splice_pipe_desc spd = { | 276 | struct splice_pipe_desc spd = { |
278 | .pages = pages, | 277 | .pages = pages, |
@@ -298,7 +297,6 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
298 | * Now fill in the holes: | 297 | * Now fill in the holes: |
299 | */ | 298 | */ |
300 | error = 0; | 299 | error = 0; |
301 | total_len = 0; | ||
302 | 300 | ||
303 | /* | 301 | /* |
304 | * Lookup the (hopefully) full range of pages we need. | 302 | * Lookup the (hopefully) full range of pages we need. |
@@ -415,43 +413,47 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
415 | 413 | ||
416 | break; | 414 | break; |
417 | } | 415 | } |
416 | } | ||
417 | fill_it: | ||
418 | /* | ||
419 | * i_size must be checked after PageUptodate. | ||
420 | */ | ||
421 | isize = i_size_read(mapping->host); | ||
422 | end_index = (isize - 1) >> PAGE_CACHE_SHIFT; | ||
423 | if (unlikely(!isize || index > end_index)) | ||
424 | break; | ||
425 | |||
426 | /* | ||
427 | * if this is the last page, see if we need to shrink | ||
428 | * the length and stop | ||
429 | */ | ||
430 | if (end_index == index) { | ||
431 | unsigned int plen; | ||
418 | 432 | ||
419 | /* | 433 | /* |
420 | * i_size must be checked after ->readpage(). | 434 | * max good bytes in this page |
421 | */ | 435 | */ |
422 | isize = i_size_read(mapping->host); | 436 | plen = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; |
423 | end_index = (isize - 1) >> PAGE_CACHE_SHIFT; | 437 | if (plen <= loff) |
424 | if (unlikely(!isize || index > end_index)) | ||
425 | break; | 438 | break; |
426 | 439 | ||
427 | /* | 440 | /* |
428 | * if this is the last page, see if we need to shrink | 441 | * force quit after adding this page |
429 | * the length and stop | ||
430 | */ | 442 | */ |
431 | if (end_index == index) { | 443 | this_len = min(this_len, plen - loff); |
432 | loff = PAGE_CACHE_SIZE - (isize & ~PAGE_CACHE_MASK); | 444 | len = this_len; |
433 | if (total_len + loff > isize) | ||
434 | break; | ||
435 | /* | ||
436 | * force quit after adding this page | ||
437 | */ | ||
438 | len = this_len; | ||
439 | this_len = min(this_len, loff); | ||
440 | loff = 0; | ||
441 | } | ||
442 | } | 445 | } |
443 | fill_it: | 446 | |
444 | partial[page_nr].offset = loff; | 447 | partial[page_nr].offset = loff; |
445 | partial[page_nr].len = this_len; | 448 | partial[page_nr].len = this_len; |
446 | len -= this_len; | 449 | len -= this_len; |
447 | total_len += this_len; | ||
448 | loff = 0; | 450 | loff = 0; |
449 | spd.nr_pages++; | 451 | spd.nr_pages++; |
450 | index++; | 452 | index++; |
451 | } | 453 | } |
452 | 454 | ||
453 | /* | 455 | /* |
454 | * Release any pages at the end, if we quit early. 'i' is how far | 456 | * Release any pages at the end, if we quit early. 'page_nr' is how far |
455 | * we got, 'nr_pages' is how many pages are in the map. | 457 | * we got, 'nr_pages' is how many pages are in the map. |
456 | */ | 458 | */ |
457 | while (page_nr < nr_pages) | 459 | while (page_nr < nr_pages) |
@@ -478,10 +480,18 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
478 | { | 480 | { |
479 | ssize_t spliced; | 481 | ssize_t spliced; |
480 | int ret; | 482 | int ret; |
483 | loff_t isize, left; | ||
484 | |||
485 | isize = i_size_read(in->f_mapping->host); | ||
486 | if (unlikely(*ppos >= isize)) | ||
487 | return 0; | ||
488 | |||
489 | left = isize - *ppos; | ||
490 | if (unlikely(left < len)) | ||
491 | len = left; | ||
481 | 492 | ||
482 | ret = 0; | 493 | ret = 0; |
483 | spliced = 0; | 494 | spliced = 0; |
484 | |||
485 | while (len) { | 495 | while (len) { |
486 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); | 496 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
487 | 497 | ||
@@ -644,7 +654,6 @@ find_page: | |||
644 | * accessed, we are now done! | 654 | * accessed, we are now done! |
645 | */ | 655 | */ |
646 | mark_page_accessed(page); | 656 | mark_page_accessed(page); |
647 | balance_dirty_pages_ratelimited(mapping); | ||
648 | out: | 657 | out: |
649 | page_cache_release(page); | 658 | page_cache_release(page); |
650 | unlock_page(page); | 659 | unlock_page(page); |
@@ -815,6 +824,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, | |||
815 | if (err) | 824 | if (err) |
816 | ret = err; | 825 | ret = err; |
817 | } | 826 | } |
827 | balance_dirty_pages_ratelimited(mapping); | ||
818 | } | 828 | } |
819 | 829 | ||
820 | return ret; | 830 | return ret; |
@@ -868,6 +878,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | |||
868 | if (err) | 878 | if (err) |
869 | ret = err; | 879 | ret = err; |
870 | } | 880 | } |
881 | balance_dirty_pages_ratelimited(mapping); | ||
871 | } | 882 | } |
872 | 883 | ||
873 | return ret; | 884 | return ret; |
@@ -922,7 +933,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
922 | struct pipe_inode_info *pipe, size_t len, | 933 | struct pipe_inode_info *pipe, size_t len, |
923 | unsigned int flags) | 934 | unsigned int flags) |
924 | { | 935 | { |
925 | loff_t isize, left; | ||
926 | int ret; | 936 | int ret; |
927 | 937 | ||
928 | if (unlikely(!in->f_op || !in->f_op->splice_read)) | 938 | if (unlikely(!in->f_op || !in->f_op->splice_read)) |
@@ -935,14 +945,6 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
935 | if (unlikely(ret < 0)) | 945 | if (unlikely(ret < 0)) |
936 | return ret; | 946 | return ret; |
937 | 947 | ||
938 | isize = i_size_read(in->f_mapping->host); | ||
939 | if (unlikely(*ppos >= isize)) | ||
940 | return 0; | ||
941 | |||
942 | left = isize - *ppos; | ||
943 | if (unlikely(left < len)) | ||
944 | len = left; | ||
945 | |||
946 | return in->f_op->splice_read(in, ppos, pipe, len, flags); | 948 | return in->f_op->splice_read(in, ppos, pipe, len, flags); |
947 | } | 949 | } |
948 | 950 | ||
@@ -1058,8 +1060,6 @@ out_release: | |||
1058 | return ret; | 1060 | return ret; |
1059 | } | 1061 | } |
1060 | 1062 | ||
1061 | EXPORT_SYMBOL(do_splice_direct); | ||
1062 | |||
1063 | /* | 1063 | /* |
1064 | * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same | 1064 | * After the inode slimming patch, i_pipe/i_bdev/i_cdev share the same |
1065 | * location, so checking ->i_pipe is not enough to verify that this is a | 1065 | * location, so checking ->i_pipe is not enough to verify that this is a |