diff options
-rw-r--r-- | fs/ext3/dir.c | 4 | ||||
-rw-r--r-- | fs/ext4/dir.c | 4 | ||||
-rw-r--r-- | fs/splice.c | 6 | ||||
-rw-r--r-- | include/linux/mm.h | 20 | ||||
-rw-r--r-- | mm/filemap.c | 10 | ||||
-rw-r--r-- | mm/readahead.c | 97 |
6 files changed, 85 insertions, 56 deletions
diff --git a/fs/ext3/dir.c b/fs/ext3/dir.c index 3c6d384a2c66..c00723a99f44 100644 --- a/fs/ext3/dir.c +++ b/fs/ext3/dir.c | |||
@@ -139,10 +139,10 @@ static int ext3_readdir(struct file * filp, | |||
139 | pgoff_t index = map_bh.b_blocknr >> | 139 | pgoff_t index = map_bh.b_blocknr >> |
140 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | 140 | (PAGE_CACHE_SHIFT - inode->i_blkbits); |
141 | if (!ra_has_index(&filp->f_ra, index)) | 141 | if (!ra_has_index(&filp->f_ra, index)) |
142 | page_cache_readahead_ondemand( | 142 | page_cache_sync_readahead( |
143 | sb->s_bdev->bd_inode->i_mapping, | 143 | sb->s_bdev->bd_inode->i_mapping, |
144 | &filp->f_ra, filp, | 144 | &filp->f_ra, filp, |
145 | NULL, index, 1); | 145 | index, 1); |
146 | filp->f_ra.prev_index = index; | 146 | filp->f_ra.prev_index = index; |
147 | bh = ext3_bread(NULL, inode, blk, 0, &err); | 147 | bh = ext3_bread(NULL, inode, blk, 0, &err); |
148 | } | 148 | } |
diff --git a/fs/ext4/dir.c b/fs/ext4/dir.c index 0a872a09fed8..3ab01c04e00c 100644 --- a/fs/ext4/dir.c +++ b/fs/ext4/dir.c | |||
@@ -138,10 +138,10 @@ static int ext4_readdir(struct file * filp, | |||
138 | pgoff_t index = map_bh.b_blocknr >> | 138 | pgoff_t index = map_bh.b_blocknr >> |
139 | (PAGE_CACHE_SHIFT - inode->i_blkbits); | 139 | (PAGE_CACHE_SHIFT - inode->i_blkbits); |
140 | if (!ra_has_index(&filp->f_ra, index)) | 140 | if (!ra_has_index(&filp->f_ra, index)) |
141 | page_cache_readahead_ondemand( | 141 | page_cache_sync_readahead( |
142 | sb->s_bdev->bd_inode->i_mapping, | 142 | sb->s_bdev->bd_inode->i_mapping, |
143 | &filp->f_ra, filp, | 143 | &filp->f_ra, filp, |
144 | NULL, index, 1); | 144 | index, 1); |
145 | filp->f_ra.prev_index = index; | 145 | filp->f_ra.prev_index = index; |
146 | bh = ext4_bread(NULL, inode, blk, 0, &err); | 146 | bh = ext4_bread(NULL, inode, blk, 0, &err); |
147 | } | 147 | } |
diff --git a/fs/splice.c b/fs/splice.c index 6ddd0329f866..22496d2a73fa 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -295,8 +295,8 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
295 | * readahead/allocate the rest and fill in the holes. | 295 | * readahead/allocate the rest and fill in the holes. |
296 | */ | 296 | */ |
297 | if (spd.nr_pages < nr_pages) | 297 | if (spd.nr_pages < nr_pages) |
298 | page_cache_readahead_ondemand(mapping, &in->f_ra, in, | 298 | page_cache_sync_readahead(mapping, &in->f_ra, in, |
299 | NULL, index, req_pages - spd.nr_pages); | 299 | index, req_pages - spd.nr_pages); |
300 | 300 | ||
301 | error = 0; | 301 | error = 0; |
302 | while (spd.nr_pages < nr_pages) { | 302 | while (spd.nr_pages < nr_pages) { |
@@ -352,7 +352,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
352 | page = pages[page_nr]; | 352 | page = pages[page_nr]; |
353 | 353 | ||
354 | if (PageReadahead(page)) | 354 | if (PageReadahead(page)) |
355 | page_cache_readahead_ondemand(mapping, &in->f_ra, in, | 355 | page_cache_async_readahead(mapping, &in->f_ra, in, |
356 | page, index, req_pages - page_nr); | 356 | page, index, req_pages - page_nr); |
357 | 357 | ||
358 | /* | 358 | /* |
diff --git a/include/linux/mm.h b/include/linux/mm.h index 3d0d7d285237..50a0ed1d1806 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h | |||
@@ -1138,12 +1138,20 @@ int do_page_cache_readahead(struct address_space *mapping, struct file *filp, | |||
1138 | pgoff_t offset, unsigned long nr_to_read); | 1138 | pgoff_t offset, unsigned long nr_to_read); |
1139 | int force_page_cache_readahead(struct address_space *mapping, struct file *filp, | 1139 | int force_page_cache_readahead(struct address_space *mapping, struct file *filp, |
1140 | pgoff_t offset, unsigned long nr_to_read); | 1140 | pgoff_t offset, unsigned long nr_to_read); |
1141 | unsigned long page_cache_readahead_ondemand(struct address_space *mapping, | 1141 | |
1142 | struct file_ra_state *ra, | 1142 | void page_cache_sync_readahead(struct address_space *mapping, |
1143 | struct file *filp, | 1143 | struct file_ra_state *ra, |
1144 | struct page *page, | 1144 | struct file *filp, |
1145 | pgoff_t offset, | 1145 | pgoff_t offset, |
1146 | unsigned long size); | 1146 | unsigned long size); |
1147 | |||
1148 | void page_cache_async_readahead(struct address_space *mapping, | ||
1149 | struct file_ra_state *ra, | ||
1150 | struct file *filp, | ||
1151 | struct page *pg, | ||
1152 | pgoff_t offset, | ||
1153 | unsigned long size); | ||
1154 | |||
1147 | unsigned long max_sane_readahead(unsigned long nr); | 1155 | unsigned long max_sane_readahead(unsigned long nr); |
1148 | 1156 | ||
1149 | /* Do stack extension */ | 1157 | /* Do stack extension */ |
diff --git a/mm/filemap.c b/mm/filemap.c index 5eb0a6b9d607..49a6fe375d01 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
@@ -894,15 +894,15 @@ void do_generic_mapping_read(struct address_space *mapping, | |||
894 | find_page: | 894 | find_page: |
895 | page = find_get_page(mapping, index); | 895 | page = find_get_page(mapping, index); |
896 | if (!page) { | 896 | if (!page) { |
897 | page_cache_readahead_ondemand(mapping, | 897 | page_cache_sync_readahead(mapping, |
898 | &ra, filp, page, | 898 | &ra, filp, |
899 | index, last_index - index); | 899 | index, last_index - index); |
900 | page = find_get_page(mapping, index); | 900 | page = find_get_page(mapping, index); |
901 | if (unlikely(page == NULL)) | 901 | if (unlikely(page == NULL)) |
902 | goto no_cached_page; | 902 | goto no_cached_page; |
903 | } | 903 | } |
904 | if (PageReadahead(page)) { | 904 | if (PageReadahead(page)) { |
905 | page_cache_readahead_ondemand(mapping, | 905 | page_cache_async_readahead(mapping, |
906 | &ra, filp, page, | 906 | &ra, filp, page, |
907 | index, last_index - index); | 907 | index, last_index - index); |
908 | } | 908 | } |
@@ -1348,14 +1348,14 @@ retry_find: | |||
1348 | */ | 1348 | */ |
1349 | if (VM_SequentialReadHint(vma)) { | 1349 | if (VM_SequentialReadHint(vma)) { |
1350 | if (!page) { | 1350 | if (!page) { |
1351 | page_cache_readahead_ondemand(mapping, ra, file, page, | 1351 | page_cache_sync_readahead(mapping, ra, file, |
1352 | vmf->pgoff, 1); | 1352 | vmf->pgoff, 1); |
1353 | page = find_lock_page(mapping, vmf->pgoff); | 1353 | page = find_lock_page(mapping, vmf->pgoff); |
1354 | if (!page) | 1354 | if (!page) |
1355 | goto no_cached_page; | 1355 | goto no_cached_page; |
1356 | } | 1356 | } |
1357 | if (PageReadahead(page)) { | 1357 | if (PageReadahead(page)) { |
1358 | page_cache_readahead_ondemand(mapping, ra, file, page, | 1358 | page_cache_async_readahead(mapping, ra, file, page, |
1359 | vmf->pgoff, 1); | 1359 | vmf->pgoff, 1); |
1360 | } | 1360 | } |
1361 | } | 1361 | } |
diff --git a/mm/readahead.c b/mm/readahead.c index 205a4a431516..3d262bb738a9 100644 --- a/mm/readahead.c +++ b/mm/readahead.c | |||
@@ -359,7 +359,7 @@ static unsigned long get_next_ra_size(struct file_ra_state *ra, | |||
359 | static unsigned long | 359 | static unsigned long |
360 | ondemand_readahead(struct address_space *mapping, | 360 | ondemand_readahead(struct address_space *mapping, |
361 | struct file_ra_state *ra, struct file *filp, | 361 | struct file_ra_state *ra, struct file *filp, |
362 | struct page *page, pgoff_t offset, | 362 | bool hit_readahead_marker, pgoff_t offset, |
363 | unsigned long req_size) | 363 | unsigned long req_size) |
364 | { | 364 | { |
365 | unsigned long max; /* max readahead pages */ | 365 | unsigned long max; /* max readahead pages */ |
@@ -387,7 +387,7 @@ ondemand_readahead(struct address_space *mapping, | |||
387 | * Standalone, small read. | 387 | * Standalone, small read. |
388 | * Read as is, and do not pollute the readahead state. | 388 | * Read as is, and do not pollute the readahead state. |
389 | */ | 389 | */ |
390 | if (!page && !sequential) { | 390 | if (!hit_readahead_marker && !sequential) { |
391 | return __do_page_cache_readahead(mapping, filp, | 391 | return __do_page_cache_readahead(mapping, filp, |
392 | offset, req_size, 0); | 392 | offset, req_size, 0); |
393 | } | 393 | } |
@@ -408,7 +408,7 @@ ondemand_readahead(struct address_space *mapping, | |||
408 | * E.g. interleaved reads. | 408 | * E.g. interleaved reads. |
409 | * Not knowing its readahead pos/size, bet on the minimal possible one. | 409 | * Not knowing its readahead pos/size, bet on the minimal possible one. |
410 | */ | 410 | */ |
411 | if (page) { | 411 | if (hit_readahead_marker) { |
412 | ra_index++; | 412 | ra_index++; |
413 | ra_size = min(4 * ra_size, max); | 413 | ra_size = min(4 * ra_size, max); |
414 | } | 414 | } |
@@ -421,50 +421,71 @@ fill_ra: | |||
421 | } | 421 | } |
422 | 422 | ||
423 | /** | 423 | /** |
424 | * page_cache_readahead_ondemand - generic file readahead | 424 | * page_cache_sync_readahead - generic file readahead |
425 | * @mapping: address_space which holds the pagecache and I/O vectors | 425 | * @mapping: address_space which holds the pagecache and I/O vectors |
426 | * @ra: file_ra_state which holds the readahead state | 426 | * @ra: file_ra_state which holds the readahead state |
427 | * @filp: passed on to ->readpage() and ->readpages() | 427 | * @filp: passed on to ->readpage() and ->readpages() |
428 | * @page: the page at @offset, or NULL if non-present | 428 | * @offset: start offset into @mapping, in pagecache page-sized units |
429 | * @offset: start offset into @mapping, in PAGE_CACHE_SIZE units | ||
430 | * @req_size: hint: total size of the read which the caller is performing in | 429 | * @req_size: hint: total size of the read which the caller is performing in |
431 | * PAGE_CACHE_SIZE units | 430 | * pagecache pages |
432 | * | 431 | * |
433 | * page_cache_readahead_ondemand() is the entry point of readahead logic. | 432 | * page_cache_sync_readahead() should be called when a cache miss happened: |
434 | * This function should be called when it is time to perform readahead: | 433 | * it will submit the read. The readahead logic may decide to piggyback more |
435 | * 1) @page == NULL | 434 | * pages onto the read request if access patterns suggest it will improve |
436 | * A cache miss happened, time for synchronous readahead. | 435 | * performance. |
437 | * 2) @page != NULL && PageReadahead(@page) | ||
438 | * A look-ahead hit occured, time for asynchronous readahead. | ||
439 | */ | 436 | */ |
440 | unsigned long | 437 | void page_cache_sync_readahead(struct address_space *mapping, |
441 | page_cache_readahead_ondemand(struct address_space *mapping, | 438 | struct file_ra_state *ra, struct file *filp, |
442 | struct file_ra_state *ra, struct file *filp, | 439 | pgoff_t offset, unsigned long req_size) |
443 | struct page *page, pgoff_t offset, | ||
444 | unsigned long req_size) | ||
445 | { | 440 | { |
446 | /* no read-ahead */ | 441 | /* no read-ahead */ |
447 | if (!ra->ra_pages) | 442 | if (!ra->ra_pages) |
448 | return 0; | 443 | return; |
449 | 444 | ||
450 | if (page) { | 445 | /* do read-ahead */ |
451 | /* | 446 | ondemand_readahead(mapping, ra, filp, false, offset, req_size); |
452 | * It can be PG_reclaim. | 447 | } |
453 | */ | 448 | EXPORT_SYMBOL_GPL(page_cache_sync_readahead); |
454 | if (PageWriteback(page)) | 449 | |
455 | return 0; | 450 | /** |
456 | 451 | * page_cache_async_readahead - file readahead for marked pages | |
457 | ClearPageReadahead(page); | 452 | * @mapping: address_space which holds the pagecache and I/O vectors |
458 | 453 | * @ra: file_ra_state which holds the readahead state | |
459 | /* | 454 | * @filp: passed on to ->readpage() and ->readpages() |
460 | * Defer asynchronous read-ahead on IO congestion. | 455 | * @page: the page at @offset which has the PG_readahead flag set |
461 | */ | 456 | * @offset: start offset into @mapping, in pagecache page-sized units |
462 | if (bdi_read_congested(mapping->backing_dev_info)) | 457 | * @req_size: hint: total size of the read which the caller is performing in |
463 | return 0; | 458 | * pagecache pages |
464 | } | 459 | * |
460 | * page_cache_async_ondemand() should be called when a page is used which | ||
461 | * has the PG_readahead flag: this is a marker to suggest that the application | ||
462 | * has used up enough of the readahead window that we should start pulling in | ||
463 | * more pages. */ | ||
464 | void | ||
465 | page_cache_async_readahead(struct address_space *mapping, | ||
466 | struct file_ra_state *ra, struct file *filp, | ||
467 | struct page *page, pgoff_t offset, | ||
468 | unsigned long req_size) | ||
469 | { | ||
470 | /* no read-ahead */ | ||
471 | if (!ra->ra_pages) | ||
472 | return; | ||
473 | |||
474 | /* | ||
475 | * Same bit is used for PG_readahead and PG_reclaim. | ||
476 | */ | ||
477 | if (PageWriteback(page)) | ||
478 | return; | ||
479 | |||
480 | ClearPageReadahead(page); | ||
481 | |||
482 | /* | ||
483 | * Defer asynchronous read-ahead on IO congestion. | ||
484 | */ | ||
485 | if (bdi_read_congested(mapping->backing_dev_info)) | ||
486 | return; | ||
465 | 487 | ||
466 | /* do read-ahead */ | 488 | /* do read-ahead */ |
467 | return ondemand_readahead(mapping, ra, filp, page, | 489 | ondemand_readahead(mapping, ra, filp, true, offset, req_size); |
468 | offset, req_size); | ||
469 | } | 490 | } |
470 | EXPORT_SYMBOL_GPL(page_cache_readahead_ondemand); | 491 | EXPORT_SYMBOL_GPL(page_cache_async_readahead); |