aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/page-flags.h2
-rw-r--r--mm/readahead.c39
2 files changed, 38 insertions, 3 deletions
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index 61df1779b2a5..9d99e7471ade 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -182,7 +182,7 @@ static inline int TestClearPage##uname(struct page *page) { return 0; }
182 182
183struct page; /* forward declaration */ 183struct page; /* forward declaration */
184 184
185TESTPAGEFLAG(Locked, locked) 185TESTPAGEFLAG(Locked, locked) TESTSETFLAG(Locked, locked)
186PAGEFLAG(Error, error) 186PAGEFLAG(Error, error)
187PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced) 187PAGEFLAG(Referenced, referenced) TESTCLEARFLAG(Referenced, referenced)
188PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty) 188PAGEFLAG(Dirty, dirty) TESTSCFLAG(Dirty, dirty) __CLEARPAGEFLAG(Dirty, dirty)
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 */
40static 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 */
57static 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);