diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/truncate.c | 34 |
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 | |||
291 | EXPORT_SYMBOL(invalidate_inode_pages); | 290 | EXPORT_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 | */ | ||
299 | static int | ||
300 | invalidate_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; | ||
318 | failed: | ||
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; |