aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorVlastimil Babka <vbabka@suse.cz>2016-03-15 17:56:18 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-03-15 19:55:16 -0400
commit7cd12b4abfd2f8f42414c520bbd051a5b7dc7a8c (patch)
treeaddc9efb62517cb685561fc50d9645bfd9a0b30a /mm
parentd435edca928805074dae005ab9a42d9fa60fc702 (diff)
mm, page_owner: track and print last migrate reason
During migration, page_owner info is now copied with the rest of the page, so the stacktrace leading to free page allocation during migration is overwritten. For debugging purposes, it might be however useful to know that the page has been migrated since its initial allocation. This might happen many times during the lifetime for different reasons and fully tracking this, especially with stacktraces would incur extra memory costs. As a compromise, store and print the migrate_reason of the last migration that occurred to the page. This is enough to distinguish compaction, numa balancing etc. Example page_owner entry after the patch: Page allocated via order 0, mask 0x24200ca(GFP_HIGHUSER_MOVABLE) PFN 628753 type Movable Block 1228 type Movable Flags 0x1fffff80040030(dirty|lru|swapbacked) [<ffffffff811682c4>] __alloc_pages_nodemask+0x134/0x230 [<ffffffff811b6325>] alloc_pages_vma+0xb5/0x250 [<ffffffff81177491>] shmem_alloc_page+0x61/0x90 [<ffffffff8117a438>] shmem_getpage_gfp+0x678/0x960 [<ffffffff8117c2b9>] shmem_fallocate+0x329/0x440 [<ffffffff811de600>] vfs_fallocate+0x140/0x230 [<ffffffff811df434>] SyS_fallocate+0x44/0x70 [<ffffffff8158cc2e>] entry_SYSCALL_64_fastpath+0x12/0x71 Page has been migrated, last migrate reason: compaction Signed-off-by: Vlastimil Babka <vbabka@suse.cz> Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com> Cc: Minchan Kim <minchan@kernel.org> Cc: Sasha Levin <sasha.levin@oracle.com> Cc: "Kirill A. Shutemov" <kirill.shutemov@linux.intel.com> Cc: Mel Gorman <mgorman@suse.de> Cc: Michal Hocko <mhocko@suse.com> Cc: Hugh Dickins <hughd@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/debug.c11
-rw-r--r--mm/migrate.c10
-rw-r--r--mm/page_owner.c17
3 files changed, 35 insertions, 3 deletions
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;