diff options
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 97 |
1 files changed, 61 insertions, 36 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 107d026f5d6e..fb52b548080d 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -62,7 +62,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) | |||
62 | total_rss << (PAGE_SHIFT-10), | 62 | total_rss << (PAGE_SHIFT-10), |
63 | data << (PAGE_SHIFT-10), | 63 | data << (PAGE_SHIFT-10), |
64 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, | 64 | mm->stack_vm << (PAGE_SHIFT-10), text, lib, |
65 | (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10, | 65 | (PTRS_PER_PTE * sizeof(pte_t) * |
66 | atomic_long_read(&mm->nr_ptes)) >> 10, | ||
66 | swap << (PAGE_SHIFT-10)); | 67 | swap << (PAGE_SHIFT-10)); |
67 | } | 68 | } |
68 | 69 | ||
@@ -83,14 +84,6 @@ unsigned long task_statm(struct mm_struct *mm, | |||
83 | return mm->total_vm; | 84 | return mm->total_vm; |
84 | } | 85 | } |
85 | 86 | ||
86 | static void pad_len_spaces(struct seq_file *m, int len) | ||
87 | { | ||
88 | len = 25 + sizeof(void*) * 6 - len; | ||
89 | if (len < 1) | ||
90 | len = 1; | ||
91 | seq_printf(m, "%*c", len, ' '); | ||
92 | } | ||
93 | |||
94 | #ifdef CONFIG_NUMA | 87 | #ifdef CONFIG_NUMA |
95 | /* | 88 | /* |
96 | * These functions are for numa_maps but called in generic **maps seq_file | 89 | * These functions are for numa_maps but called in generic **maps seq_file |
@@ -268,7 +261,6 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | |||
268 | unsigned long long pgoff = 0; | 261 | unsigned long long pgoff = 0; |
269 | unsigned long start, end; | 262 | unsigned long start, end; |
270 | dev_t dev = 0; | 263 | dev_t dev = 0; |
271 | int len; | ||
272 | const char *name = NULL; | 264 | const char *name = NULL; |
273 | 265 | ||
274 | if (file) { | 266 | if (file) { |
@@ -286,7 +278,8 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | |||
286 | if (stack_guard_page_end(vma, end)) | 278 | if (stack_guard_page_end(vma, end)) |
287 | end -= PAGE_SIZE; | 279 | end -= PAGE_SIZE; |
288 | 280 | ||
289 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", | 281 | seq_setwidth(m, 25 + sizeof(void *) * 6 - 1); |
282 | seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu ", | ||
290 | start, | 283 | start, |
291 | end, | 284 | end, |
292 | flags & VM_READ ? 'r' : '-', | 285 | flags & VM_READ ? 'r' : '-', |
@@ -294,14 +287,14 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | |||
294 | flags & VM_EXEC ? 'x' : '-', | 287 | flags & VM_EXEC ? 'x' : '-', |
295 | flags & VM_MAYSHARE ? 's' : 'p', | 288 | flags & VM_MAYSHARE ? 's' : 'p', |
296 | pgoff, | 289 | pgoff, |
297 | MAJOR(dev), MINOR(dev), ino, &len); | 290 | MAJOR(dev), MINOR(dev), ino); |
298 | 291 | ||
299 | /* | 292 | /* |
300 | * Print the dentry name for named mappings, and a | 293 | * Print the dentry name for named mappings, and a |
301 | * special [heap] marker for the heap: | 294 | * special [heap] marker for the heap: |
302 | */ | 295 | */ |
303 | if (file) { | 296 | if (file) { |
304 | pad_len_spaces(m, len); | 297 | seq_pad(m, ' '); |
305 | seq_path(m, &file->f_path, "\n"); | 298 | seq_path(m, &file->f_path, "\n"); |
306 | goto done; | 299 | goto done; |
307 | } | 300 | } |
@@ -333,7 +326,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | |||
333 | name = "[stack]"; | 326 | name = "[stack]"; |
334 | } else { | 327 | } else { |
335 | /* Thread stack in /proc/PID/maps */ | 328 | /* Thread stack in /proc/PID/maps */ |
336 | pad_len_spaces(m, len); | 329 | seq_pad(m, ' '); |
337 | seq_printf(m, "[stack:%d]", tid); | 330 | seq_printf(m, "[stack:%d]", tid); |
338 | } | 331 | } |
339 | } | 332 | } |
@@ -341,7 +334,7 @@ show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | |||
341 | 334 | ||
342 | done: | 335 | done: |
343 | if (name) { | 336 | if (name) { |
344 | pad_len_spaces(m, len); | 337 | seq_pad(m, ' '); |
345 | seq_puts(m, name); | 338 | seq_puts(m, name); |
346 | } | 339 | } |
347 | seq_putc(m, '\n'); | 340 | seq_putc(m, '\n'); |
@@ -505,9 +498,9 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
505 | pte_t *pte; | 498 | pte_t *pte; |
506 | spinlock_t *ptl; | 499 | spinlock_t *ptl; |
507 | 500 | ||
508 | if (pmd_trans_huge_lock(pmd, vma) == 1) { | 501 | if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { |
509 | smaps_pte_entry(*(pte_t *)pmd, addr, HPAGE_PMD_SIZE, walk); | 502 | smaps_pte_entry(*(pte_t *)pmd, addr, HPAGE_PMD_SIZE, walk); |
510 | spin_unlock(&walk->mm->page_table_lock); | 503 | spin_unlock(ptl); |
511 | mss->anonymous_thp += HPAGE_PMD_SIZE; | 504 | mss->anonymous_thp += HPAGE_PMD_SIZE; |
512 | return 0; | 505 | return 0; |
513 | } | 506 | } |
@@ -561,6 +554,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma) | |||
561 | [ilog2(VM_NONLINEAR)] = "nl", | 554 | [ilog2(VM_NONLINEAR)] = "nl", |
562 | [ilog2(VM_ARCH_1)] = "ar", | 555 | [ilog2(VM_ARCH_1)] = "ar", |
563 | [ilog2(VM_DONTDUMP)] = "dd", | 556 | [ilog2(VM_DONTDUMP)] = "dd", |
557 | #ifdef CONFIG_MEM_SOFT_DIRTY | ||
558 | [ilog2(VM_SOFTDIRTY)] = "sd", | ||
559 | #endif | ||
564 | [ilog2(VM_MIXEDMAP)] = "mm", | 560 | [ilog2(VM_MIXEDMAP)] = "mm", |
565 | [ilog2(VM_HUGEPAGE)] = "hg", | 561 | [ilog2(VM_HUGEPAGE)] = "hg", |
566 | [ilog2(VM_NOHUGEPAGE)] = "nh", | 562 | [ilog2(VM_NOHUGEPAGE)] = "nh", |
@@ -740,6 +736,9 @@ static inline void clear_soft_dirty(struct vm_area_struct *vma, | |||
740 | ptent = pte_file_clear_soft_dirty(ptent); | 736 | ptent = pte_file_clear_soft_dirty(ptent); |
741 | } | 737 | } |
742 | 738 | ||
739 | if (vma->vm_flags & VM_SOFTDIRTY) | ||
740 | vma->vm_flags &= ~VM_SOFTDIRTY; | ||
741 | |||
743 | set_pte_at(vma->vm_mm, addr, pte, ptent); | 742 | set_pte_at(vma->vm_mm, addr, pte, ptent); |
744 | #endif | 743 | #endif |
745 | } | 744 | } |
@@ -938,6 +937,8 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, | |||
938 | frame = pte_pfn(pte); | 937 | frame = pte_pfn(pte); |
939 | flags = PM_PRESENT; | 938 | flags = PM_PRESENT; |
940 | page = vm_normal_page(vma, addr, pte); | 939 | page = vm_normal_page(vma, addr, pte); |
940 | if (pte_soft_dirty(pte)) | ||
941 | flags2 |= __PM_SOFT_DIRTY; | ||
941 | } else if (is_swap_pte(pte)) { | 942 | } else if (is_swap_pte(pte)) { |
942 | swp_entry_t entry; | 943 | swp_entry_t entry; |
943 | if (pte_swp_soft_dirty(pte)) | 944 | if (pte_swp_soft_dirty(pte)) |
@@ -949,13 +950,15 @@ static void pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, | |||
949 | if (is_migration_entry(entry)) | 950 | if (is_migration_entry(entry)) |
950 | page = migration_entry_to_page(entry); | 951 | page = migration_entry_to_page(entry); |
951 | } else { | 952 | } else { |
952 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); | 953 | if (vma->vm_flags & VM_SOFTDIRTY) |
954 | flags2 |= __PM_SOFT_DIRTY; | ||
955 | *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); | ||
953 | return; | 956 | return; |
954 | } | 957 | } |
955 | 958 | ||
956 | if (page && !PageAnon(page)) | 959 | if (page && !PageAnon(page)) |
957 | flags |= PM_FILE; | 960 | flags |= PM_FILE; |
958 | if (pte_soft_dirty(pte)) | 961 | if ((vma->vm_flags & VM_SOFTDIRTY)) |
959 | flags2 |= __PM_SOFT_DIRTY; | 962 | flags2 |= __PM_SOFT_DIRTY; |
960 | 963 | ||
961 | *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags); | 964 | *pme = make_pme(PM_PFRAME(frame) | PM_STATUS2(pm->v2, flags2) | flags); |
@@ -974,7 +977,7 @@ static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *p | |||
974 | *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) | 977 | *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) |
975 | | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT); | 978 | | PM_STATUS2(pm->v2, pmd_flags2) | PM_PRESENT); |
976 | else | 979 | else |
977 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); | 980 | *pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, pmd_flags2)); |
978 | } | 981 | } |
979 | #else | 982 | #else |
980 | static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, | 983 | static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
@@ -988,16 +991,21 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
988 | { | 991 | { |
989 | struct vm_area_struct *vma; | 992 | struct vm_area_struct *vma; |
990 | struct pagemapread *pm = walk->private; | 993 | struct pagemapread *pm = walk->private; |
994 | spinlock_t *ptl; | ||
991 | pte_t *pte; | 995 | pte_t *pte; |
992 | int err = 0; | 996 | int err = 0; |
993 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); | 997 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT(pm->v2)); |
994 | 998 | ||
995 | /* find the first VMA at or above 'addr' */ | 999 | /* find the first VMA at or above 'addr' */ |
996 | vma = find_vma(walk->mm, addr); | 1000 | vma = find_vma(walk->mm, addr); |
997 | if (vma && pmd_trans_huge_lock(pmd, vma) == 1) { | 1001 | if (vma && pmd_trans_huge_lock(pmd, vma, &ptl) == 1) { |
998 | int pmd_flags2; | 1002 | int pmd_flags2; |
999 | 1003 | ||
1000 | pmd_flags2 = (pmd_soft_dirty(*pmd) ? __PM_SOFT_DIRTY : 0); | 1004 | if ((vma->vm_flags & VM_SOFTDIRTY) || pmd_soft_dirty(*pmd)) |
1005 | pmd_flags2 = __PM_SOFT_DIRTY; | ||
1006 | else | ||
1007 | pmd_flags2 = 0; | ||
1008 | |||
1001 | for (; addr != end; addr += PAGE_SIZE) { | 1009 | for (; addr != end; addr += PAGE_SIZE) { |
1002 | unsigned long offset; | 1010 | unsigned long offset; |
1003 | 1011 | ||
@@ -1008,19 +1016,24 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
1008 | if (err) | 1016 | if (err) |
1009 | break; | 1017 | break; |
1010 | } | 1018 | } |
1011 | spin_unlock(&walk->mm->page_table_lock); | 1019 | spin_unlock(ptl); |
1012 | return err; | 1020 | return err; |
1013 | } | 1021 | } |
1014 | 1022 | ||
1015 | if (pmd_trans_unstable(pmd)) | 1023 | if (pmd_trans_unstable(pmd)) |
1016 | return 0; | 1024 | return 0; |
1017 | for (; addr != end; addr += PAGE_SIZE) { | 1025 | for (; addr != end; addr += PAGE_SIZE) { |
1026 | int flags2; | ||
1018 | 1027 | ||
1019 | /* check to see if we've left 'vma' behind | 1028 | /* check to see if we've left 'vma' behind |
1020 | * and need a new, higher one */ | 1029 | * and need a new, higher one */ |
1021 | if (vma && (addr >= vma->vm_end)) { | 1030 | if (vma && (addr >= vma->vm_end)) { |
1022 | vma = find_vma(walk->mm, addr); | 1031 | vma = find_vma(walk->mm, addr); |
1023 | pme = make_pme(PM_NOT_PRESENT(pm->v2)); | 1032 | if (vma && (vma->vm_flags & VM_SOFTDIRTY)) |
1033 | flags2 = __PM_SOFT_DIRTY; | ||
1034 | else | ||
1035 | flags2 = 0; | ||
1036 | pme = make_pme(PM_NOT_PRESENT(pm->v2) | PM_STATUS2(pm->v2, flags2)); | ||
1024 | } | 1037 | } |
1025 | 1038 | ||
1026 | /* check that 'vma' actually covers this address, | 1039 | /* check that 'vma' actually covers this address, |
@@ -1044,13 +1057,15 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
1044 | 1057 | ||
1045 | #ifdef CONFIG_HUGETLB_PAGE | 1058 | #ifdef CONFIG_HUGETLB_PAGE |
1046 | static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, | 1059 | static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, struct pagemapread *pm, |
1047 | pte_t pte, int offset) | 1060 | pte_t pte, int offset, int flags2) |
1048 | { | 1061 | { |
1049 | if (pte_present(pte)) | 1062 | if (pte_present(pte)) |
1050 | *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) | 1063 | *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) | |
1051 | | PM_STATUS2(pm->v2, 0) | PM_PRESENT); | 1064 | PM_STATUS2(pm->v2, flags2) | |
1065 | PM_PRESENT); | ||
1052 | else | 1066 | else |
1053 | *pme = make_pme(PM_NOT_PRESENT(pm->v2)); | 1067 | *pme = make_pme(PM_NOT_PRESENT(pm->v2) | |
1068 | PM_STATUS2(pm->v2, flags2)); | ||
1054 | } | 1069 | } |
1055 | 1070 | ||
1056 | /* This function walks within one hugetlb entry in the single call */ | 1071 | /* This function walks within one hugetlb entry in the single call */ |
@@ -1059,12 +1074,22 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | |||
1059 | struct mm_walk *walk) | 1074 | struct mm_walk *walk) |
1060 | { | 1075 | { |
1061 | struct pagemapread *pm = walk->private; | 1076 | struct pagemapread *pm = walk->private; |
1077 | struct vm_area_struct *vma; | ||
1062 | int err = 0; | 1078 | int err = 0; |
1079 | int flags2; | ||
1063 | pagemap_entry_t pme; | 1080 | pagemap_entry_t pme; |
1064 | 1081 | ||
1082 | vma = find_vma(walk->mm, addr); | ||
1083 | WARN_ON_ONCE(!vma); | ||
1084 | |||
1085 | if (vma && (vma->vm_flags & VM_SOFTDIRTY)) | ||
1086 | flags2 = __PM_SOFT_DIRTY; | ||
1087 | else | ||
1088 | flags2 = 0; | ||
1089 | |||
1065 | for (; addr != end; addr += PAGE_SIZE) { | 1090 | for (; addr != end; addr += PAGE_SIZE) { |
1066 | int offset = (addr & ~hmask) >> PAGE_SHIFT; | 1091 | int offset = (addr & ~hmask) >> PAGE_SHIFT; |
1067 | huge_pte_to_pagemap_entry(&pme, pm, *pte, offset); | 1092 | huge_pte_to_pagemap_entry(&pme, pm, *pte, offset, flags2); |
1068 | err = add_to_pagemap(addr, &pme, pm); | 1093 | err = add_to_pagemap(addr, &pme, pm); |
1069 | if (err) | 1094 | if (err) |
1070 | return err; | 1095 | return err; |
@@ -1293,7 +1318,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, | |||
1293 | 1318 | ||
1294 | md = walk->private; | 1319 | md = walk->private; |
1295 | 1320 | ||
1296 | if (pmd_trans_huge_lock(pmd, md->vma) == 1) { | 1321 | if (pmd_trans_huge_lock(pmd, md->vma, &ptl) == 1) { |
1297 | pte_t huge_pte = *(pte_t *)pmd; | 1322 | pte_t huge_pte = *(pte_t *)pmd; |
1298 | struct page *page; | 1323 | struct page *page; |
1299 | 1324 | ||
@@ -1301,7 +1326,7 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, | |||
1301 | if (page) | 1326 | if (page) |
1302 | gather_stats(page, md, pte_dirty(huge_pte), | 1327 | gather_stats(page, md, pte_dirty(huge_pte), |
1303 | HPAGE_PMD_SIZE/PAGE_SIZE); | 1328 | HPAGE_PMD_SIZE/PAGE_SIZE); |
1304 | spin_unlock(&walk->mm->page_table_lock); | 1329 | spin_unlock(ptl); |
1305 | return 0; | 1330 | return 0; |
1306 | } | 1331 | } |
1307 | 1332 | ||
@@ -1359,8 +1384,8 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) | |||
1359 | struct mm_struct *mm = vma->vm_mm; | 1384 | struct mm_struct *mm = vma->vm_mm; |
1360 | struct mm_walk walk = {}; | 1385 | struct mm_walk walk = {}; |
1361 | struct mempolicy *pol; | 1386 | struct mempolicy *pol; |
1362 | int n; | 1387 | char buffer[64]; |
1363 | char buffer[50]; | 1388 | int nid; |
1364 | 1389 | ||
1365 | if (!mm) | 1390 | if (!mm) |
1366 | return 0; | 1391 | return 0; |
@@ -1430,9 +1455,9 @@ static int show_numa_map(struct seq_file *m, void *v, int is_pid) | |||
1430 | if (md->writeback) | 1455 | if (md->writeback) |
1431 | seq_printf(m, " writeback=%lu", md->writeback); | 1456 | seq_printf(m, " writeback=%lu", md->writeback); |
1432 | 1457 | ||
1433 | for_each_node_state(n, N_MEMORY) | 1458 | for_each_node_state(nid, N_MEMORY) |
1434 | if (md->node[n]) | 1459 | if (md->node[nid]) |
1435 | seq_printf(m, " N%d=%lu", n, md->node[n]); | 1460 | seq_printf(m, " N%d=%lu", nid, md->node[nid]); |
1436 | out: | 1461 | out: |
1437 | seq_putc(m, '\n'); | 1462 | seq_putc(m, '\n'); |
1438 | 1463 | ||