aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mm/truncate.c34
1 files changed, 32 insertions, 2 deletions
diff --git a/mm/truncate.c b/mm/truncate.c
index 8fde6580657e..f4edbc179d14 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -287,9 +287,39 @@ unsigned long invalidate_inode_pages(struct address_space *mapping)
287{ 287{
288 return invalidate_mapping_pages(mapping, 0, ~0UL); 288 return invalidate_mapping_pages(mapping, 0, ~0UL);
289} 289}
290
291EXPORT_SYMBOL(invalidate_inode_pages); 290EXPORT_SYMBOL(invalidate_inode_pages);
292 291
292/*
293 * This is like invalidate_complete_page(), except it ignores the page's
294 * refcount. We do this because invalidate_inode_pages2() needs stronger
295 * invalidation guarantees, and cannot afford to leave pages behind because
296 * shrink_list() has a temp ref on them, or because they're transiently sitting
297 * in the lru_cache_add() pagevecs.
298 */
299static int
300invalidate_complete_page2(struct address_space *mapping, struct page *page)
301{
302 if (page->mapping != mapping)
303 return 0;
304
305 if (PagePrivate(page) && !try_to_release_page(page, 0))
306 return 0;
307
308 write_lock_irq(&mapping->tree_lock);
309 if (PageDirty(page))
310 goto failed;
311
312 BUG_ON(PagePrivate(page));
313 __remove_from_page_cache(page);
314 write_unlock_irq(&mapping->tree_lock);
315 ClearPageUptodate(page);
316 page_cache_release(page); /* pagecache ref */
317 return 1;
318failed:
319 write_unlock_irq(&mapping->tree_lock);
320 return 0;
321}
322
293/** 323/**
294 * invalidate_inode_pages2_range - remove range of pages from an address_space 324 * invalidate_inode_pages2_range - remove range of pages from an address_space
295 * @mapping: the address_space 325 * @mapping: the address_space
@@ -356,7 +386,7 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
356 } 386 }
357 } 387 }
358 was_dirty = test_clear_page_dirty(page); 388 was_dirty = test_clear_page_dirty(page);
359 if (!invalidate_complete_page(mapping, page)) { 389 if (!invalidate_complete_page2(mapping, page)) {
360 if (was_dirty) 390 if (was_dirty)
361 set_page_dirty(page); 391 set_page_dirty(page);
362 ret = -EIO; 392 ret = -EIO;