aboutsummaryrefslogtreecommitdiffstats
path: root/mm/truncate.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/truncate.c')
-rw-r--r--mm/truncate.c49
1 files changed, 40 insertions, 9 deletions
diff --git a/mm/truncate.c b/mm/truncate.c
index 9bfb8e853860..5df947de7654 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -52,6 +52,33 @@ static inline void truncate_partial_page(struct page *page, unsigned partial)
52} 52}
53 53
54/* 54/*
55 * This cancels just the dirty bit on the kernel page itself, it
56 * does NOT actually remove dirty bits on any mmap's that may be
57 * around. It also leaves the page tagged dirty, so any sync
58 * activity will still find it on the dirty lists, and in particular,
59 * clear_page_dirty_for_io() will still look at the dirty bits in
60 * the VM.
61 *
62 * Doing this should *normally* only ever be done when a page
63 * is truncated, and is not actually mapped anywhere at all. However,
64 * fs/buffer.c does this when it notices that somebody has cleaned
65 * out all the buffers on a page without actually doing it through
66 * the VM. Can you say "ext3 is horribly ugly"? Tought you could.
67 */
68void cancel_dirty_page(struct page *page, unsigned int account_size)
69{
70 if (TestClearPageDirty(page)) {
71 struct address_space *mapping = page->mapping;
72 if (mapping && mapping_cap_account_dirty(mapping)) {
73 dec_zone_page_state(page, NR_FILE_DIRTY);
74 if (account_size)
75 task_io_account_cancelled_write(account_size);
76 }
77 }
78}
79EXPORT_SYMBOL(cancel_dirty_page);
80
81/*
55 * If truncate cannot remove the fs-private metadata from the page, the page 82 * If truncate cannot remove the fs-private metadata from the page, the page
56 * becomes anonymous. It will be left on the LRU and may even be mapped into 83 * becomes anonymous. It will be left on the LRU and may even be mapped into
57 * user pagetables if we're racing with filemap_nopage(). 84 * user pagetables if we're racing with filemap_nopage().
@@ -67,11 +94,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
67 if (page->mapping != mapping) 94 if (page->mapping != mapping)
68 return; 95 return;
69 96
97 cancel_dirty_page(page, PAGE_CACHE_SIZE);
98
70 if (PagePrivate(page)) 99 if (PagePrivate(page))
71 do_invalidatepage(page, 0); 100 do_invalidatepage(page, 0);
72 101
73 if (test_clear_page_dirty(page))
74 task_io_account_cancelled_write(PAGE_CACHE_SIZE);
75 ClearPageUptodate(page); 102 ClearPageUptodate(page);
76 ClearPageMappedToDisk(page); 103 ClearPageMappedToDisk(page);
77 remove_from_page_cache(page); 104 remove_from_page_cache(page);
@@ -321,6 +348,15 @@ failed:
321 return 0; 348 return 0;
322} 349}
323 350
351static int do_launder_page(struct address_space *mapping, struct page *page)
352{
353 if (!PageDirty(page))
354 return 0;
355 if (page->mapping != mapping || mapping->a_ops->launder_page == NULL)
356 return 0;
357 return mapping->a_ops->launder_page(page);
358}
359
324/** 360/**
325 * invalidate_inode_pages2_range - remove range of pages from an address_space 361 * invalidate_inode_pages2_range - remove range of pages from an address_space
326 * @mapping: the address_space 362 * @mapping: the address_space
@@ -350,7 +386,6 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
350 for (i = 0; !ret && i < pagevec_count(&pvec); i++) { 386 for (i = 0; !ret && i < pagevec_count(&pvec); i++) {
351 struct page *page = pvec.pages[i]; 387 struct page *page = pvec.pages[i];
352 pgoff_t page_index; 388 pgoff_t page_index;
353 int was_dirty;
354 389
355 lock_page(page); 390 lock_page(page);
356 if (page->mapping != mapping) { 391 if (page->mapping != mapping) {
@@ -386,18 +421,14 @@ int invalidate_inode_pages2_range(struct address_space *mapping,
386 PAGE_CACHE_SIZE, 0); 421 PAGE_CACHE_SIZE, 0);
387 } 422 }
388 } 423 }
389 was_dirty = test_clear_page_dirty(page); 424 ret = do_launder_page(mapping, page);
390 if (!invalidate_complete_page2(mapping, page)) { 425 if (ret == 0 && !invalidate_complete_page2(mapping, page))
391 if (was_dirty)
392 set_page_dirty(page);
393 ret = -EIO; 426 ret = -EIO;
394 }
395 unlock_page(page); 427 unlock_page(page);
396 } 428 }
397 pagevec_release(&pvec); 429 pagevec_release(&pvec);
398 cond_resched(); 430 cond_resched();
399 } 431 }
400 WARN_ON_ONCE(ret);
401 return ret; 432 return ret;
402} 433}
403EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range); 434EXPORT_SYMBOL_GPL(invalidate_inode_pages2_range);