diff options
-rw-r--r-- | include/linux/migrate.h | 6 | ||||
-rw-r--r-- | include/linux/page_ext.h | 1 | ||||
-rw-r--r-- | include/linux/page_owner.h | 9 | ||||
-rw-r--r-- | mm/debug.c | 11 | ||||
-rw-r--r-- | mm/migrate.c | 10 | ||||
-rw-r--r-- | mm/page_owner.c | 17 |
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 */ | ||
31 | extern char *migrate_reason_names[MR_TYPES]; | ||
32 | |||
29 | #ifdef CONFIG_MIGRATION | 33 | #ifdef CONFIG_MIGRATION |
30 | 34 | ||
31 | extern void putback_movable_pages(struct list_head *l); | 35 | extern 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); |
13 | extern gfp_t __get_page_owner_gfp(struct page *page); | 13 | extern gfp_t __get_page_owner_gfp(struct page *page); |
14 | extern void __copy_page_owner(struct page *oldpage, struct page *newpage); | 14 | extern void __copy_page_owner(struct page *oldpage, struct page *newpage); |
15 | extern void __set_page_owner_migrate_reason(struct page *page, int reason); | ||
15 | 16 | ||
16 | static inline void reset_page_owner(struct page *page, unsigned int order) | 17 | static 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 | } |
42 | static 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 |
42 | static inline void reset_page_owner(struct page *page, unsigned int order) | 48 | static 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) | |||
53 | static inline void copy_page_owner(struct page *oldpage, struct page *newpage) | 59 | static inline void copy_page_owner(struct page *oldpage, struct page *newpage) |
54 | { | 60 | { |
55 | } | 61 | } |
62 | static 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 | ||
17 | char *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 | |||
16 | const struct trace_print_flags pageflag_names[] = { | 27 | const 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 | ||
961 | out: | 963 | out: |
962 | if (rc != -EAGAIN) { | 964 | if (rc != -EAGAIN) { |
@@ -1021,7 +1023,7 @@ out: | |||
1021 | static int unmap_and_move_huge_page(new_page_t get_new_page, | 1023 | static 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 | ||
11 | static bool page_owner_disabled = true; | 12 | static 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 | ||
82 | void __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 | |||
80 | gfp_t __get_page_owner_gfp(struct page *page) | 89 | gfp_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; |