Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b9ea2515 authored by Konstantin Khlebnikov's avatar Konstantin Khlebnikov Committed by Linus Torvalds
Browse files

page_writeback: clean up mess around cancel_dirty_page()



This patch replaces cancel_dirty_page() with a helper function
account_page_cleaned() which only updates counters.  It's called from
truncate_complete_page() and from try_to_free_buffers() (hack for ext3).
Page is locked in both cases, page-lock protects against concurrent
dirtiers: see commit 2d6d7f98 ("mm: protect set_page_dirty() from
ongoing truncation").

Delete_from_page_cache() shouldn't be called for dirty pages, they must
be handled by caller (either written or truncated).  This patch treats
final dirty accounting fixup at the end of __delete_from_page_cache() as
a debug check and adds WARN_ON_ONCE() around it.  If something removes
dirty pages without proper handling that might be a bug and unwritten
data might be lost.

Hugetlbfs has no dirty pages accounting, ClearPageDirty() is enough
here.

cancel_dirty_page() in nfs_wb_page_cancel() is redundant.  This is
helper for nfs_invalidate_page() and it's called only in case complete
invalidation.

The mess was started in v2.6.20 after commits 46d2277c ("Clean up
and make try_to_free_buffers() not race with dirty pages") and
3e67c098 ("truncate: clear page dirtiness before running
try_to_free_buffers()") first was reverted right in v2.6.20 in commit
ecdfc978 ("Resurrect 'try_to_free_buffers()' VM hackery"), second in
v2.6.25 commit a2b34564 ("Fix dirty page accounting leak with ext3
data=journal").

Custom fixes were introduced between these points.  NFS in v2.6.23, commit
1b3b4a1a ("NFS: Fix a write request leak in nfs_invalidate_page()").
Kludge in __delete_from_page_cache() in v2.6.24, commit 3a692790 ("Do
dirty page accounting when removing a page from the page cache").  Since
v2.6.25 all of them are redundant.

[akpm@linux-foundation.org: coding-style fixes]
Signed-off-by: default avatarKonstantin Khlebnikov <khlebnikov@yandex-team.ru>
Cc: Tejun Heo <tj@kernel.org>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent ca0984ca
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -55,7 +55,9 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
	if (PagePrivate(page))
		page->mapping->a_ops->invalidatepage(page, 0, PAGE_CACHE_SIZE);

	cancel_dirty_page(page, PAGE_SIZE);
	if (TestClearPageDirty(page))
		account_page_cleaned(page, mapping);

	ClearPageMappedToDisk(page);
	ll_delete_from_page_cache(page);
}
+2 −2
Original line number Diff line number Diff line
@@ -3243,8 +3243,8 @@ int try_to_free_buffers(struct page *page)
	 * to synchronise against __set_page_dirty_buffers and prevent the
	 * dirty bit from being lost.
	 */
	if (ret)
		cancel_dirty_page(page, PAGE_CACHE_SIZE);
	if (ret && TestClearPageDirty(page))
		account_page_cleaned(page, mapping);
	spin_unlock(&mapping->private_lock);
out:
	if (buffers_to_free) {
+1 −1
Original line number Diff line number Diff line
@@ -319,7 +319,7 @@ static int hugetlbfs_write_end(struct file *file, struct address_space *mapping,

static void truncate_huge_page(struct page *page)
{
	cancel_dirty_page(page, /* No IO accounting for huge pages? */0);
	ClearPageDirty(page);
	ClearPageUptodate(page);
	delete_from_page_cache(page);
}
+0 −5
Original line number Diff line number Diff line
@@ -1876,11 +1876,6 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
		 * request from the inode / page_private pointer and
		 * release it */
		nfs_inode_remove_request(req);
		/*
		 * In case nfs_inode_remove_request has marked the
		 * page as being dirty
		 */
		cancel_dirty_page(page, PAGE_CACHE_SIZE);
		nfs_unlock_and_release_request(req);
	}

+2 −0
Original line number Diff line number Diff line
@@ -1294,9 +1294,11 @@ int __set_page_dirty_no_writeback(struct page *page);
int redirty_page_for_writepage(struct writeback_control *wbc,
				struct page *page);
void account_page_dirtied(struct page *page, struct address_space *mapping);
void account_page_cleaned(struct page *page, struct address_space *mapping);
int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);

int get_cmdline(struct task_struct *task, char *buffer, int buflen);

/* Is the vma a continuation of the stack vma above it? */
Loading