[PATCH] possible fix

From: Greg Thelen
Date: Fri Sep 18 2015 - 03:38:14 EST


Assume that newpage is dirty and charged to memcg. So the memcg's dirty
page count was incremented for the page. Migration's move_to_new_page()
indirectly calls migrate_page_copy(newpage, page), which decrements
page->mem_cgroup's dirty page count, but because newpage->mem_cgroup is
not yet set, __set_page_dirty_nobuffers() cannot reincrement the memcg
dirty page count. Later move_to_new_page() calls mem_cgroup_migrate()
which finally sets newpage->mem_cgroup, but the dirty page count is
never reincremented, despite PG_dirty=1. Time passes and
account_page_cleaned(newpage) is called which decrements a
non-incremented page->mem_cgroup dirty page count, causing underflow.

Because we're exchanging one dirty page for another, we might be able to
avoid decrementing and immediately reincrementing the memcg's dirty
count.

This is an alternative (ugly) fix which survives light testing. It
temporarily sets up newpage's memcg so that __set_page_dirty_nobuffers()
can increment memcg's dirty page count. I need to study this approach
more carefully before claiming it's a good fix.

Not-Yet-Signed-off-by: Greg Thelen <gthelen@xxxxxxxxxx>
---
mm/migrate.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/mm/migrate.c b/mm/migrate.c
index c3cb566af3e2..6268eb8b6fd5 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -734,6 +734,11 @@ static int move_to_new_page(struct page *newpage, struct page *page,
if (!trylock_page(newpage))
BUG();

+#ifdef CONFIG_MEMCG
+ VM_BUG_ON(newpage->mem_cgroup);
+ newpage->mem_cgroup = page->mem_cgroup;
+#endif
+
/* Prepare mapping for the new page.*/
newpage->index = page->index;
newpage->mapping = page->mapping;
@@ -755,6 +760,10 @@ static int move_to_new_page(struct page *newpage, struct page *page,
else
rc = fallback_migrate_page(mapping, newpage, page, mode);

+#ifdef CONFIG_MEMCG
+ newpage->mem_cgroup = NULL;
+#endif
+
if (rc != MIGRATEPAGE_SUCCESS) {
newpage->mapping = NULL;
} else {
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/