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); |