|
@@ -31,6 +31,41 @@ EXPORT_SYMBOL_GPL(file_ra_state_init);
|
|
|
|
|
|
#define list_to_page(head) (list_entry((head)->prev, struct page, lru))
|
|
#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 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 (PagePrivate(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
|
|
* read_cache_pages - populate an address space with some pages & start reads against them
|
|
* @mapping: the address_space
|
|
* @mapping: the address_space
|
|
@@ -52,14 +87,14 @@ int read_cache_pages(struct address_space *mapping, struct list_head *pages,
|
|
list_del(&page->lru);
|
|
list_del(&page->lru);
|
|
if (add_to_page_cache_lru(page, mapping,
|
|
if (add_to_page_cache_lru(page, mapping,
|
|
page->index, GFP_KERNEL)) {
|
|
page->index, GFP_KERNEL)) {
|
|
- page_cache_release(page);
|
|
|
|
|
|
+ read_cache_pages_invalidate_page(mapping, page);
|
|
continue;
|
|
continue;
|
|
}
|
|
}
|
|
page_cache_release(page);
|
|
page_cache_release(page);
|
|
|
|
|
|
ret = filler(data, page);
|
|
ret = filler(data, page);
|
|
if (unlikely(ret)) {
|
|
if (unlikely(ret)) {
|
|
- put_pages_list(pages);
|
|
|
|
|
|
+ read_cache_pages_invalidate_pages(mapping, pages);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
task_io_account_read(PAGE_CACHE_SIZE);
|
|
task_io_account_read(PAGE_CACHE_SIZE);
|