aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/migrate.h6
-rw-r--r--include/linux/page_ext.h1
-rw-r--r--include/linux/page_owner.h9
-rw-r--r--mm/debug.c11
-rw-r--r--mm/migrate.c10
-rw-r--r--mm/page_owner.c17
6 files changed, 50 insertions, 4 deletions
diff --git a/include/linux/migrate.h b/include/linux/migrate.h
index cac1c0904d5f..9b50325e4ddf 100644
--- a/include/linux/migrate.h
+++ b/include/linux/migrate.h
@@ -23,9 +23,13 @@ enum migrate_reason {
23 MR_SYSCALL, /* also applies to cpusets */ 23 MR_SYSCALL, /* also applies to cpusets */
24 MR_MEMPOLICY_MBIND, 24 MR_MEMPOLICY_MBIND,
25 MR_NUMA_MISPLACED, 25 MR_NUMA_MISPLACED,
26 MR_CMA 26 MR_CMA,
27 MR_TYPES
27}; 28};
28 29
30/* In mm/debug.c; also keep sync with include/trace/events/migrate.h */
31extern char *migrate_reason_names[MR_TYPES];
32
29#ifdef CONFIG_MIGRATION 33#ifdef CONFIG_MIGRATION
30 34
31extern void putback_movable_pages(struct list_head *l); 35extern void putback_movable_pages(struct list_head *l);
diff --git a/include/linux/page_ext.h b/include/linux/page_ext.h
index 17f118a82854..e1fe7cf5bddf 100644
--- a/include/linux/page_ext.h
+++ b/include/linux/page_ext.h
@@ -45,6 +45,7 @@ struct page_ext {
45 unsigned int order; 45 unsigned int order;
46 gfp_t gfp_mask; 46 gfp_t gfp_mask;
47 unsigned int nr_entries; 47 unsigned int nr_entries;
48 int last_migrate_reason;
48 unsigned long trace_entries[8]; 49 unsigned long trace_entries[8];
49#endif 50#endif
50}; 51};
diff --git a/include/linux/page_owner.h b/include/linux/page_owner.h
index 6440daab4ef8..555893bf13d7 100644
--- a/include/linux/page_owner.h
+++ b/include/linux/page_owner.h
@@ -12,6 +12,7 @@ extern void __set_page_owner(struct page *page,
12 unsigned int order, gfp_t gfp_mask); 12 unsigned int order, gfp_t gfp_mask);
13extern gfp_t __get_page_owner_gfp(struct page *page); 13extern gfp_t __get_page_owner_gfp(struct page *page);
14extern void __copy_page_owner(struct page *oldpage, struct page *newpage); 14extern void __copy_page_owner(struct page *oldpage, struct page *newpage);
15extern void __set_page_owner_migrate_reason(struct page *page, int reason);
15 16
16static inline void reset_page_owner(struct page *page, unsigned int order) 17static inline void reset_page_owner(struct page *page, unsigned int order)
17{ 18{
@@ -38,6 +39,11 @@ static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
38 if (static_branch_unlikely(&page_owner_inited)) 39 if (static_branch_unlikely(&page_owner_inited))
39 __copy_page_owner(oldpage, newpage); 40 __copy_page_owner(oldpage, newpage);
40} 41}
42static inline void set_page_owner_migrate_reason(struct page *page, int reason)
43{
44 if (static_branch_unlikely(&page_owner_inited))
45 __set_page_owner_migrate_reason(page, reason);
46}
41#else 47#else
42static inline void reset_page_owner(struct page *page, unsigned int order) 48static inline void reset_page_owner(struct page *page, unsigned int order)
43{ 49{
@@ -53,5 +59,8 @@ static inline gfp_t get_page_owner_gfp(struct page *page)
53static inline void copy_page_owner(struct page *oldpage, struct page *newpage) 59static inline void copy_page_owner(struct page *oldpage, struct page *newpage)
54{ 60{
55} 61}
62static inline void set_page_owner_migrate_reason(struct page *page, int reason)
63{
64}
56#endif /* CONFIG_PAGE_OWNER */ 65#endif /* CONFIG_PAGE_OWNER */
57#endif /* __LINUX_PAGE_OWNER_H */ 66#endif /* __LINUX_PAGE_OWNER_H */
diff --git a/mm/debug.c b/mm/debug.c
index 231e1452a912..78dc54877075 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -10,9 +10,20 @@
10#include <linux/trace_events.h> 10#include <linux/trace_events.h>
11#include <linux/memcontrol.h> 11#include <linux/memcontrol.h>
12#include <trace/events/mmflags.h> 12#include <trace/events/mmflags.h>
13#include <linux/migrate.h>
13 14
14#include "internal.h" 15#include "internal.h"
15 16
17char *migrate_reason_names[MR_TYPES] = {
18 "compaction",
19 "memory_failure",
20 "memory_hotplug",
21 "syscall_or_cpuset",
22 "mempolicy_mbind",
23 "numa_misplaced",
24 "cma",
25};
26
16const struct trace_print_flags pageflag_names[] = { 27const struct trace_print_flags pageflag_names[] = {
17 __def_pageflag_names, 28 __def_pageflag_names,
18 {0, NULL} 29 {0, NULL}
diff --git a/mm/migrate.c b/mm/migrate.c
index 8133805431ba..432ecd0172cd 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -955,8 +955,10 @@ static ICE_noinline int unmap_and_move(new_page_t get_new_page,
955 } 955 }
956 956
957 rc = __unmap_and_move(page, newpage, force, mode); 957 rc = __unmap_and_move(page, newpage, force, mode);
958 if (rc == MIGRATEPAGE_SUCCESS) 958 if (rc == MIGRATEPAGE_SUCCESS) {
959 put_new_page = NULL; 959 put_new_page = NULL;
960 set_page_owner_migrate_reason(newpage, reason);
961 }
960 962
961out: 963out:
962 if (rc != -EAGAIN) { 964 if (rc != -EAGAIN) {
@@ -1021,7 +1023,7 @@ out:
1021static int unmap_and_move_huge_page(new_page_t get_new_page, 1023static int unmap_and_move_huge_page(new_page_t get_new_page,
1022 free_page_t put_new_page, unsigned long private, 1024 free_page_t put_new_page, unsigned long private,
1023 struct page *hpage, int force, 1025 struct page *hpage, int force,
1024 enum migrate_mode mode) 1026 enum migrate_mode mode, int reason)
1025{ 1027{
1026 int rc = -EAGAIN; 1028 int rc = -EAGAIN;
1027 int *result = NULL; 1029 int *result = NULL;
@@ -1079,6 +1081,7 @@ put_anon:
1079 if (rc == MIGRATEPAGE_SUCCESS) { 1081 if (rc == MIGRATEPAGE_SUCCESS) {
1080 hugetlb_cgroup_migrate(hpage, new_hpage); 1082 hugetlb_cgroup_migrate(hpage, new_hpage);
1081 put_new_page = NULL; 1083 put_new_page = NULL;
1084 set_page_owner_migrate_reason(new_hpage, reason);
1082 } 1085 }
1083 1086
1084 unlock_page(hpage); 1087 unlock_page(hpage);
@@ -1151,7 +1154,7 @@ int migrate_pages(struct list_head *from, new_page_t get_new_page,
1151 if (PageHuge(page)) 1154 if (PageHuge(page))
1152 rc = unmap_and_move_huge_page(get_new_page, 1155 rc = unmap_and_move_huge_page(get_new_page,
1153 put_new_page, private, page, 1156 put_new_page, private, page,
1154 pass > 2, mode); 1157 pass > 2, mode, reason);
1155 else 1158 else
1156 rc = unmap_and_move(get_new_page, put_new_page, 1159 rc = unmap_and_move(get_new_page, put_new_page,
1157 private, page, pass > 2, mode, 1160 private, page, pass > 2, mode,
@@ -1842,6 +1845,7 @@ fail_putback:
1842 set_page_memcg(new_page, page_memcg(page)); 1845 set_page_memcg(new_page, page_memcg(page));
1843 set_page_memcg(page, NULL); 1846 set_page_memcg(page, NULL);
1844 page_remove_rmap(page, true); 1847 page_remove_rmap(page, true);
1848 set_page_owner_migrate_reason(new_page, MR_NUMA_MISPLACED);
1845 1849
1846 spin_unlock(ptl); 1850 spin_unlock(ptl);
1847 mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end); 1851 mmu_notifier_invalidate_range_end(mm, mmun_start, mmun_end);
diff --git a/mm/page_owner.c b/mm/page_owner.c
index 774b55623212..a57068cfe52f 100644
--- a/mm/page_owner.c
+++ b/mm/page_owner.c
@@ -6,6 +6,7 @@
6#include <linux/stacktrace.h> 6#include <linux/stacktrace.h>
7#include <linux/page_owner.h> 7#include <linux/page_owner.h>
8#include <linux/jump_label.h> 8#include <linux/jump_label.h>
9#include <linux/migrate.h>
9#include "internal.h" 10#include "internal.h"
10 11
11static bool page_owner_disabled = true; 12static bool page_owner_disabled = true;
@@ -73,10 +74,18 @@ void __set_page_owner(struct page *page, unsigned int order, gfp_t gfp_mask)
73 page_ext->order = order; 74 page_ext->order = order;
74 page_ext->gfp_mask = gfp_mask; 75 page_ext->gfp_mask = gfp_mask;
75 page_ext->nr_entries = trace.nr_entries; 76 page_ext->nr_entries = trace.nr_entries;
77 page_ext->last_migrate_reason = -1;
76 78
77 __set_bit(PAGE_EXT_OWNER, &page_ext->flags); 79 __set_bit(PAGE_EXT_OWNER, &page_ext->flags);
78} 80}
79 81
82void __set_page_owner_migrate_reason(struct page *page, int reason)
83{
84 struct page_ext *page_ext = lookup_page_ext(page);
85
86 page_ext->last_migrate_reason = reason;
87}
88
80gfp_t __get_page_owner_gfp(struct page *page) 89gfp_t __get_page_owner_gfp(struct page *page)
81{ 90{
82 struct page_ext *page_ext = lookup_page_ext(page); 91 struct page_ext *page_ext = lookup_page_ext(page);
@@ -151,6 +160,14 @@ print_page_owner(char __user *buf, size_t count, unsigned long pfn,
151 if (ret >= count) 160 if (ret >= count)
152 goto err; 161 goto err;
153 162
163 if (page_ext->last_migrate_reason != -1) {
164 ret += snprintf(kbuf + ret, count - ret,
165 "Page has been migrated, last migrate reason: %s\n",
166 migrate_reason_names[page_ext->last_migrate_reason]);
167 if (ret >= count)
168 goto err;
169 }
170
154 ret += snprintf(kbuf + ret, count - ret, "\n"); 171 ret += snprintf(kbuf + ret, count - ret, "\n");
155 if (ret >= count) 172 if (ret >= count)
156 goto err; 173 goto err;