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