Skip to contentSkip to conversation

mm: Migrate misplaced page

tip:sched/numa tip-bot for Lee Schermerhorn 1 participant 1 message May 18, 2012

Subsystems (3)
lore
Share & tools
lore
#0 lore raw
Commit-ID:  4783af477d3da0e2643cf2f0619265fdf12f29f4
Gitweb:     http://git.kernel.org/tip/4783af477d3da0e2643cf2f0619265fdf12f29f4
Author:     Lee Schermerhorn <[email protected]>
AuthorDate: Wed, 11 Jan 2012 16:31:57 +0100
Committer:  Ingo Molnar <[email protected]>
CommitDate: Fri, 18 May 2012 08:16:18 +0200

mm: Migrate misplaced page

This patch adds a new function migrate_misplaced_page() to mm/migrate.c [where most of the other page migration functions live] to migrate a misplaced page to a specified destination node. This function will be called from the fault path. Because we already know the destination node for the migration, we allocate pages directly rather than rerunning the policy node computation in alloc_page_vma().

Since the fault path holds an extra reference from other migration paths, introduce a new migration_mode (MIGRATE_FAULT) to communicate this.

The patch adds the function check_migrate_misplaced_page() to migrate.c to check whether a page is "misplaced" -- i.e. on a node different from what the policy for (vma, address) dictates. This check involves accessing the vma policy, so we only do this if:

* page has zero mapcount [no pte references]
* page is not in writeback
* page is up to date
* page's mapping has a migratepage a_op [no fallback!]

If these checks are satisfied, the page will be migrated to the "correct" node, if possible. If migration fails for any reason, we just use the original page.

Subsequent patches will hook the fault handlers [anon, and possibly file and/or shmem] to check_migrate_misplaced_page().

[ fixed memcg use-after free ]

[ removed the weird ignore page count on migrate stuff with the
new migrate_mode and strict accounting ]

Cc Suresh Siddha <[email protected]>
Cc Paul Turner <[email protected]>
Cc Dan Smith <[email protected]>
Cc Bharata B Rao <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Rik van Riel <[email protected]>
Cc Andrea Arcangeli <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Linus Torvalds <[email protected]>
---
 include/linux/mempolicy.h    |   18 +-----
 include/linux/migrate.h      |   14 +++++
 include/linux/migrate_mode.h |    3 +
 mm/mempolicy.c               |   19 ++++++
 mm/migrate.c                 |  130 +++++++++++++++++++++++++++++++++++++++++-
 5 files changed, 167 insertions(+), 17 deletions(-)
include/linux/mempolicy.h +2 -16
index f005c00..c970840 100644
@@ -78,6 +78,7 @@ enum mpol_rebind_step {
 #include <linux/spinlock.h>
 #include <linux/nodemask.h>
 #include <linux/pagemap.h>
+#include <linux/migrate.h>
 
 struct mm_struct;
 
@@ -246,22 +247,7 @@ extern int mpol_parse_str(char *str, struct mempolicy **mpol, int no_context);
 extern int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
 			int no_context);
 
-/* Check if a vma is migratable */
-static inline int vma_migratable(struct vm_area_struct *vma)
-{
-	if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
-		return 0;
-	/*
-	 * Migration allocates pages in the highest zone. If we cannot
-	 * do so then migration (at least from node to node) is not
-	 * possible.
-	 */
-	if (vma->vm_file &&
-		gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
-								< policy_zone)
-			return 0;
-	return 1;
-}
+extern int vma_migratable(struct vm_area_struct *);
 
 extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long);
 
include/linux/migrate.h +14 -0
index 9e00dc9..0a0dbc0 100644
@@ -32,6 +32,8 @@ extern int migrate_huge_page_move_mapping(struct address_space *mapping,
 				  struct page *newpage, struct page *page);
 
 extern int migrate_pages_unmap_only(struct list_head *);
+extern struct page *migrate_misplaced_page(struct page *,
+			struct mm_struct *, int);
 #else
 
 static inline void putback_lru_pages(struct list_head *l) {}
@@ -71,4 +73,16 @@ static inline int migrate_pages_unmap_only(struct list_head *l)
 #define fail_migrate_page NULL
 
 #endif /* CONFIG_MIGRATION */
+
+#if defined(CONFIG_MIGRATION) && defined(CONFIG_NUMA)
+extern struct page *check_migrate_misplaced_page(struct page *,
+			struct vm_area_struct *, unsigned long);
+#else
+static inline struct page *check_migrate_misplaced_page(struct page *page,
+			struct vm_area_struct *vma, unsigned long addr)
+{
+	return page;
+}
+#endif
+
 #endif /* _LINUX_MIGRATE_H */
include/linux/migrate_mode.h +3 -0
index ebf3d89..9694347 100644
@@ -6,11 +6,14 @@
  *	on most operations but not ->writepage as the potential stall time
  *	is too significant
  * MIGRATE_SYNC will block when migrating pages
+ * MIGRATE_FAULT called from the fault path to migrate-on-fault for mempolicy
+ * 	this path has an extra reference count
  */
 enum migrate_mode {
 	MIGRATE_ASYNC,
 	MIGRATE_SYNC_LIGHT,
 	MIGRATE_SYNC,
+	MIGRATE_FAULT,
 };
 
 #endif		/* MIGRATE_MODE_H_INCLUDED */
mm/mempolicy.c +19 -0
index 651b7a3..b60c991 100644
@@ -464,6 +464,25 @@ static const struct mempolicy_operations mpol_ops[MPOL_MAX] = {
 static void migrate_page_add(struct page *page, struct list_head *pagelist,
 				unsigned long flags);
 
+/*
+ * Check whether a vma is migratable
+ */
+int vma_migratable(struct vm_area_struct *vma)
+{
+	if (vma->vm_flags & (VM_IO|VM_HUGETLB|VM_PFNMAP|VM_RESERVED))
+		return 0;
+	/*
+	 * Migration allocates pages in the highest zone. If we cannot
+	 * do so then migration (at least from node to node) is not
+	 * possible.
+	 */
+	if (vma->vm_file &&
+		gfp_zone(mapping_gfp_mask(vma->vm_file->f_mapping))
+								< policy_zone)
+			return 0;
+	return 1;
+}
+
 struct mempol_walk_data {
 	struct vm_area_struct *vma;
 	const nodemask_t *nodes;
mm/migrate.c +129 -1

139 lines not on this page · raw message