diff options
| author | Ingo Molnar <mingo@elte.hu> | 2009-04-08 19:02:50 +0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2009-04-08 19:02:57 +0400 |
| commit | ff96e612cba32510e263e17b213235fe5746397e (patch) | |
| tree | a8df57d76b10e0901a4fb76cd2987eb9826a560a /mm/readahead.c | |
| parent | cd84a42f315e50edd454c27a3da3951ccd3d735a (diff) | |
| parent | 577c9c456f0e1371cbade38eaf91ae8e8a308555 (diff) | |
| download | linux-ff96e612cba32510e263e17b213235fe5746397e.tar.xz | |
Merge commit 'v2.6.30-rc1' into core/urgent
Merge reason: need latest upstream to queue up dependent fix
Signed-off-by: Ingo Molnar <mingo@elte.hu>
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); #define list_to_page(head) (list_entry((head)->prev, struct page, lru)) +/* + * see if a page needs releasing upon read_cache_pages() failure + * - the caller of read_cache_pages() may have set PG_private or PG_fscache + * before calling, such as the NFS fs marking pages that are cached locally + * on disk, thus we need to give the fs a chance to clean up in the event of + * an error + */ +static void read_cache_pages_invalidate_page(struct address_space *mapping, + struct page *page) +{ + if (page_has_private(page)) { + if (!trylock_page(page)) + BUG(); + page->mapping = mapping; + do_invalidatepage(page, 0); + page->mapping = NULL; + unlock_page(page); + } + page_cache_release(page); +} + +/* + * release a list of pages, invalidating them first if need be + */ +static void read_cache_pages_invalidate_pages(struct address_space *mapping, + struct list_head *pages) +{ + struct page *victim; + + while (!list_empty(pages)) { + victim = list_to_page(pages); + list_del(&victim->lru); + read_cache_pages_invalidate_page(mapping, victim); + } +} + /** * read_cache_pages - populate an address space with some pages & start reads against them * @mapping: the address_space @@ -52,14 +88,14 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages, list_del(&page->lru); if (add_to_page_cache_lru(page, mapping, page->index, GFP_KERNEL)) { - page_cache_release(page); + read_cache_pages_invalidate_page(mapping, page); continue; } page_cache_release(page); ret = filler(data, page); if (unlikely(ret)) { - put_pages_list(pages); + read_cache_pages_invalidate_pages(mapping, pages); break; } task_io_account_read(PAGE_CACHE_SIZE); |
