diff options
Diffstat (limited to 'mm/readahead.c')
| -rw-r--r-- | mm/readahead.c | 40 |
1 files changed, 38 insertions, 2 deletions
diff --git a/mm/readahead.c b/mm/readahead.c index 9ce303d4b810..133b6d525513 100644 --- a/mm/readahead.c +++ b/mm/readahead.c | |||
| @@ -31,6 +31,42 @@ EXPORT_SYMBOL_GPL(file_ra_state_init); | |||
| 31 | 31 | ||
| 32 | #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) | 32 | #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) |
| 33 | 33 | ||
| 34 | /* | ||
| 35 | * see if a page needs releasing upon read_cache_pages() failure | ||
| 36 | * - the caller of read_cache_pages() may have set PG_private or PG_fscache | ||
| 37 | * before calling, such as the NFS fs marking pages that are cached locally | ||
| 38 | * on disk, thus we need to give the fs a chance to clean up in the event of | ||
| 39 | * an error | ||
| 40 | */ | ||
| 41 | static void read_cache_pages_invalidate_page(struct address_space *mapping, | ||
| 42 | struct page *page) | ||
| 43 | { | ||
| 44 | if (page_has_private(page)) { | ||
| 45 | if (!trylock_page(page)) | ||
| 46 | BUG(); | ||
| 47 | page->mapping = mapping; | ||
| 48 | do_invalidatepage(page, 0); | ||
| 49 | page->mapping = NULL; | ||
| 50 | unlock_page(page); | ||
| 51 | } | ||
| 52 | page_cache_release(page); | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * release a list of pages, invalidating them first if need be | ||
| 57 | */ | ||
| 58 | static void read_cache_pages_invalidate_pages(struct address_space *mapping, | ||
| 59 | struct list_head *pages) | ||
| 60 | { | ||
| 61 | struct page *victim; | ||
| 62 | |||
| 63 | while (!list_empty(pages)) { | ||
| 64 | victim = list_to_page(pages); | ||
| 65 | list_del(&victim->lru); | ||
| 66 | read_cache_pages_invalidate_page(mapping, victim); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 34 | /** | 70 | /** |
| 35 | * read_cache_pages - populate an address space with some pages & start reads against them | 71 | * read_cache_pages - populate an address space with some pages & start reads against them |
| 36 | * @mapping: the address_space | 72 | * @mapping: the address_space |
| @@ -52,14 +88,14 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages, | |||
| 52 | list_del(&page->lru); | 88 | list_del(&page->lru); |
| 53 | if (add_to_page_cache_lru(page, mapping, | 89 | if (add_to_page_cache_lru(page, mapping, |
| 54 | page->index, GFP_KERNEL)) { | 90 | page->index, GFP_KERNEL)) { |
| 55 | page_cache_release(page); | 91 | read_cache_pages_invalidate_page(mapping, page); |
| 56 | continue; | 92 | continue; |
| 57 | } | 93 | } |
| 58 | page_cache_release(page); | 94 | page_cache_release(page); |
| 59 | 95 | ||
| 60 | ret = filler(data, page); | 96 | ret = filler(data, page); |
| 61 | if (unlikely(ret)) { | 97 | if (unlikely(ret)) { |
| 62 | put_pages_list(pages); | 98 | read_cache_pages_invalidate_pages(mapping, pages); |
| 63 | break; | 99 | break; |
| 64 | } | 100 | } |
| 65 | task_io_account_read(PAGE_CACHE_SIZE); | 101 | task_io_account_read(PAGE_CACHE_SIZE); |
