diff options
Diffstat (limited to 'mm/truncate.c')
| -rw-r--r-- | mm/truncate.c | 31 | 
1 files changed, 23 insertions, 8 deletions
diff --git a/mm/truncate.c b/mm/truncate.c index 9bfb8e853860..ecdfdcc50522 100644 --- a/mm/truncate.c +++ b/mm/truncate.c  | |||
| @@ -51,6 +51,26 @@ static inline void truncate_partial_page(struct page *page, unsigned partial) | |||
| 51 | do_invalidatepage(page, partial); | 51 | do_invalidatepage(page, partial); | 
| 52 | } | 52 | } | 
| 53 | 53 | ||
| 54 | void cancel_dirty_page(struct page *page, unsigned int account_size) | ||
| 55 | { | ||
| 56 | /* If we're cancelling the page, it had better not be mapped any more */ | ||
| 57 | if (page_mapped(page)) { | ||
| 58 | static unsigned int warncount; | ||
| 59 | |||
| 60 | WARN_ON(++warncount < 5); | ||
| 61 | } | ||
| 62 | |||
| 63 | if (TestClearPageDirty(page)) { | ||
| 64 | struct address_space *mapping = page->mapping; | ||
| 65 | if (mapping && mapping_cap_account_dirty(mapping)) { | ||
| 66 | dec_zone_page_state(page, NR_FILE_DIRTY); | ||
| 67 | if (account_size) | ||
| 68 | task_io_account_cancelled_write(account_size); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | EXPORT_SYMBOL(cancel_dirty_page); | ||
| 73 | |||
| 54 | /* | 74 | /* | 
| 55 | * If truncate cannot remove the fs-private metadata from the page, the page | 75 | * 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 | 76 | * becomes anonymous. It will be left on the LRU and may even be mapped into | 
| @@ -67,11 +87,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page) | |||
| 67 | if (page->mapping != mapping) | 87 | if (page->mapping != mapping) | 
| 68 | return; | 88 | return; | 
| 69 | 89 | ||
| 90 | cancel_dirty_page(page, PAGE_CACHE_SIZE); | ||
| 91 | |||
| 70 | if (PagePrivate(page)) | 92 | if (PagePrivate(page)) | 
| 71 | do_invalidatepage(page, 0); | 93 | do_invalidatepage(page, 0); | 
| 72 | 94 | ||
| 73 | if (test_clear_page_dirty(page)) | ||
| 74 | task_io_account_cancelled_write(PAGE_CACHE_SIZE); | ||
| 75 | ClearPageUptodate(page); | 95 | ClearPageUptodate(page); | 
| 76 | ClearPageMappedToDisk(page); | 96 | ClearPageMappedToDisk(page); | 
| 77 | remove_from_page_cache(page); | 97 | remove_from_page_cache(page); | 
| @@ -350,7 +370,6 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
| 350 | for (i = 0; !ret && i < pagevec_count(&pvec); i++) { | 370 | for (i = 0; !ret && i < pagevec_count(&pvec); i++) { | 
| 351 | struct page *page = pvec.pages[i]; | 371 | struct page *page = pvec.pages[i]; | 
| 352 | pgoff_t page_index; | 372 | pgoff_t page_index; | 
| 353 | int was_dirty; | ||
| 354 | 373 | ||
| 355 | lock_page(page); | 374 | lock_page(page); | 
| 356 | if (page->mapping != mapping) { | 375 | if (page->mapping != mapping) { | 
| @@ -386,12 +405,8 @@ int invalidate_inode_pages2_range(struct address_space *mapping, | |||
| 386 | PAGE_CACHE_SIZE, 0); | 405 | PAGE_CACHE_SIZE, 0); | 
| 387 | } | 406 | } | 
| 388 | } | 407 | } | 
| 389 | was_dirty = test_clear_page_dirty(page); | 408 | if (!invalidate_complete_page2(mapping, page)) | 
| 390 | if (!invalidate_complete_page2(mapping, page)) { | ||
| 391 | if (was_dirty) | ||
| 392 | set_page_dirty(page); | ||
| 393 | ret = -EIO; | 409 | ret = -EIO; | 
| 394 | } | ||
| 395 | unlock_page(page); | 410 | unlock_page(page); | 
| 396 | } | 411 | } | 
| 397 | pagevec_release(&pvec); | 412 | pagevec_release(&pvec); | 
