diff options
Diffstat (limited to 'fs/proc/task_mmu.c')
-rw-r--r-- | fs/proc/task_mmu.c | 357 |
1 files changed, 261 insertions, 96 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 7dcd2a250495..9694cc283511 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -209,16 +209,20 @@ static int do_maps_open(struct inode *inode, struct file *file, | |||
209 | return ret; | 209 | return ret; |
210 | } | 210 | } |
211 | 211 | ||
212 | static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | 212 | static void |
213 | show_map_vma(struct seq_file *m, struct vm_area_struct *vma, int is_pid) | ||
213 | { | 214 | { |
214 | struct mm_struct *mm = vma->vm_mm; | 215 | struct mm_struct *mm = vma->vm_mm; |
215 | struct file *file = vma->vm_file; | 216 | struct file *file = vma->vm_file; |
217 | struct proc_maps_private *priv = m->private; | ||
218 | struct task_struct *task = priv->task; | ||
216 | vm_flags_t flags = vma->vm_flags; | 219 | vm_flags_t flags = vma->vm_flags; |
217 | unsigned long ino = 0; | 220 | unsigned long ino = 0; |
218 | unsigned long long pgoff = 0; | 221 | unsigned long long pgoff = 0; |
219 | unsigned long start, end; | 222 | unsigned long start, end; |
220 | dev_t dev = 0; | 223 | dev_t dev = 0; |
221 | int len; | 224 | int len; |
225 | const char *name = NULL; | ||
222 | 226 | ||
223 | if (file) { | 227 | if (file) { |
224 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; | 228 | struct inode *inode = vma->vm_file->f_path.dentry->d_inode; |
@@ -252,36 +256,57 @@ static void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) | |||
252 | if (file) { | 256 | if (file) { |
253 | pad_len_spaces(m, len); | 257 | pad_len_spaces(m, len); |
254 | seq_path(m, &file->f_path, "\n"); | 258 | seq_path(m, &file->f_path, "\n"); |
255 | } else { | 259 | goto done; |
256 | const char *name = arch_vma_name(vma); | 260 | } |
257 | if (!name) { | 261 | |
258 | if (mm) { | 262 | name = arch_vma_name(vma); |
259 | if (vma->vm_start <= mm->brk && | 263 | if (!name) { |
260 | vma->vm_end >= mm->start_brk) { | 264 | pid_t tid; |
261 | name = "[heap]"; | 265 | |
262 | } else if (vma->vm_start <= mm->start_stack && | 266 | if (!mm) { |
263 | vma->vm_end >= mm->start_stack) { | 267 | name = "[vdso]"; |
264 | name = "[stack]"; | 268 | goto done; |
265 | } | 269 | } |
270 | |||
271 | if (vma->vm_start <= mm->brk && | ||
272 | vma->vm_end >= mm->start_brk) { | ||
273 | name = "[heap]"; | ||
274 | goto done; | ||
275 | } | ||
276 | |||
277 | tid = vm_is_stack(task, vma, is_pid); | ||
278 | |||
279 | if (tid != 0) { | ||
280 | /* | ||
281 | * Thread stack in /proc/PID/task/TID/maps or | ||
282 | * the main process stack. | ||
283 | */ | ||
284 | if (!is_pid || (vma->vm_start <= mm->start_stack && | ||
285 | vma->vm_end >= mm->start_stack)) { | ||
286 | name = "[stack]"; | ||
266 | } else { | 287 | } else { |
267 | name = "[vdso]"; | 288 | /* Thread stack in /proc/PID/maps */ |
289 | pad_len_spaces(m, len); | ||
290 | seq_printf(m, "[stack:%d]", tid); | ||
268 | } | 291 | } |
269 | } | 292 | } |
270 | if (name) { | 293 | } |
271 | pad_len_spaces(m, len); | 294 | |
272 | seq_puts(m, name); | 295 | done: |
273 | } | 296 | if (name) { |
297 | pad_len_spaces(m, len); | ||
298 | seq_puts(m, name); | ||
274 | } | 299 | } |
275 | seq_putc(m, '\n'); | 300 | seq_putc(m, '\n'); |
276 | } | 301 | } |
277 | 302 | ||
278 | static int show_map(struct seq_file *m, void *v) | 303 | static int show_map(struct seq_file *m, void *v, int is_pid) |
279 | { | 304 | { |
280 | struct vm_area_struct *vma = v; | 305 | struct vm_area_struct *vma = v; |
281 | struct proc_maps_private *priv = m->private; | 306 | struct proc_maps_private *priv = m->private; |
282 | struct task_struct *task = priv->task; | 307 | struct task_struct *task = priv->task; |
283 | 308 | ||
284 | show_map_vma(m, vma); | 309 | show_map_vma(m, vma, is_pid); |
285 | 310 | ||
286 | if (m->count < m->size) /* vma is copied successfully */ | 311 | if (m->count < m->size) /* vma is copied successfully */ |
287 | m->version = (vma != get_gate_vma(task->mm)) | 312 | m->version = (vma != get_gate_vma(task->mm)) |
@@ -289,20 +314,49 @@ static int show_map(struct seq_file *m, void *v) | |||
289 | return 0; | 314 | return 0; |
290 | } | 315 | } |
291 | 316 | ||
317 | static int show_pid_map(struct seq_file *m, void *v) | ||
318 | { | ||
319 | return show_map(m, v, 1); | ||
320 | } | ||
321 | |||
322 | static int show_tid_map(struct seq_file *m, void *v) | ||
323 | { | ||
324 | return show_map(m, v, 0); | ||
325 | } | ||
326 | |||
292 | static const struct seq_operations proc_pid_maps_op = { | 327 | static const struct seq_operations proc_pid_maps_op = { |
293 | .start = m_start, | 328 | .start = m_start, |
294 | .next = m_next, | 329 | .next = m_next, |
295 | .stop = m_stop, | 330 | .stop = m_stop, |
296 | .show = show_map | 331 | .show = show_pid_map |
297 | }; | 332 | }; |
298 | 333 | ||
299 | static int maps_open(struct inode *inode, struct file *file) | 334 | static const struct seq_operations proc_tid_maps_op = { |
335 | .start = m_start, | ||
336 | .next = m_next, | ||
337 | .stop = m_stop, | ||
338 | .show = show_tid_map | ||
339 | }; | ||
340 | |||
341 | static int pid_maps_open(struct inode *inode, struct file *file) | ||
300 | { | 342 | { |
301 | return do_maps_open(inode, file, &proc_pid_maps_op); | 343 | return do_maps_open(inode, file, &proc_pid_maps_op); |
302 | } | 344 | } |
303 | 345 | ||
304 | const struct file_operations proc_maps_operations = { | 346 | static int tid_maps_open(struct inode *inode, struct file *file) |
305 | .open = maps_open, | 347 | { |
348 | return do_maps_open(inode, file, &proc_tid_maps_op); | ||
349 | } | ||
350 | |||
351 | const struct file_operations proc_pid_maps_operations = { | ||
352 | .open = pid_maps_open, | ||
353 | .read = seq_read, | ||
354 | .llseek = seq_lseek, | ||
355 | .release = seq_release_private, | ||
356 | }; | ||
357 | |||
358 | const struct file_operations proc_tid_maps_operations = { | ||
359 | .open = tid_maps_open, | ||
306 | .read = seq_read, | 360 | .read = seq_read, |
307 | .llseek = seq_lseek, | 361 | .llseek = seq_lseek, |
308 | .release = seq_release_private, | 362 | .release = seq_release_private, |
@@ -394,21 +448,15 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
394 | pte_t *pte; | 448 | pte_t *pte; |
395 | spinlock_t *ptl; | 449 | spinlock_t *ptl; |
396 | 450 | ||
397 | spin_lock(&walk->mm->page_table_lock); | 451 | if (pmd_trans_huge_lock(pmd, vma) == 1) { |
398 | if (pmd_trans_huge(*pmd)) { | 452 | smaps_pte_entry(*(pte_t *)pmd, addr, HPAGE_PMD_SIZE, walk); |
399 | if (pmd_trans_splitting(*pmd)) { | ||
400 | spin_unlock(&walk->mm->page_table_lock); | ||
401 | wait_split_huge_page(vma->anon_vma, pmd); | ||
402 | } else { | ||
403 | smaps_pte_entry(*(pte_t *)pmd, addr, | ||
404 | HPAGE_PMD_SIZE, walk); | ||
405 | spin_unlock(&walk->mm->page_table_lock); | ||
406 | mss->anonymous_thp += HPAGE_PMD_SIZE; | ||
407 | return 0; | ||
408 | } | ||
409 | } else { | ||
410 | spin_unlock(&walk->mm->page_table_lock); | 453 | spin_unlock(&walk->mm->page_table_lock); |
454 | mss->anonymous_thp += HPAGE_PMD_SIZE; | ||
455 | return 0; | ||
411 | } | 456 | } |
457 | |||
458 | if (pmd_trans_unstable(pmd)) | ||
459 | return 0; | ||
412 | /* | 460 | /* |
413 | * The mmap_sem held all the way back in m_start() is what | 461 | * The mmap_sem held all the way back in m_start() is what |
414 | * keeps khugepaged out of here and from collapsing things | 462 | * keeps khugepaged out of here and from collapsing things |
@@ -422,7 +470,7 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
422 | return 0; | 470 | return 0; |
423 | } | 471 | } |
424 | 472 | ||
425 | static int show_smap(struct seq_file *m, void *v) | 473 | static int show_smap(struct seq_file *m, void *v, int is_pid) |
426 | { | 474 | { |
427 | struct proc_maps_private *priv = m->private; | 475 | struct proc_maps_private *priv = m->private; |
428 | struct task_struct *task = priv->task; | 476 | struct task_struct *task = priv->task; |
@@ -440,7 +488,7 @@ static int show_smap(struct seq_file *m, void *v) | |||
440 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) | 488 | if (vma->vm_mm && !is_vm_hugetlb_page(vma)) |
441 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); | 489 | walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); |
442 | 490 | ||
443 | show_map_vma(m, vma); | 491 | show_map_vma(m, vma, is_pid); |
444 | 492 | ||
445 | seq_printf(m, | 493 | seq_printf(m, |
446 | "Size: %8lu kB\n" | 494 | "Size: %8lu kB\n" |
@@ -479,20 +527,49 @@ static int show_smap(struct seq_file *m, void *v) | |||
479 | return 0; | 527 | return 0; |
480 | } | 528 | } |
481 | 529 | ||
530 | static int show_pid_smap(struct seq_file *m, void *v) | ||
531 | { | ||
532 | return show_smap(m, v, 1); | ||
533 | } | ||
534 | |||
535 | static int show_tid_smap(struct seq_file *m, void *v) | ||
536 | { | ||
537 | return show_smap(m, v, 0); | ||
538 | } | ||
539 | |||
482 | static const struct seq_operations proc_pid_smaps_op = { | 540 | static const struct seq_operations proc_pid_smaps_op = { |
483 | .start = m_start, | 541 | .start = m_start, |
484 | .next = m_next, | 542 | .next = m_next, |
485 | .stop = m_stop, | 543 | .stop = m_stop, |
486 | .show = show_smap | 544 | .show = show_pid_smap |
545 | }; | ||
546 | |||
547 | static const struct seq_operations proc_tid_smaps_op = { | ||
548 | .start = m_start, | ||
549 | .next = m_next, | ||
550 | .stop = m_stop, | ||
551 | .show = show_tid_smap | ||
487 | }; | 552 | }; |
488 | 553 | ||
489 | static int smaps_open(struct inode *inode, struct file *file) | 554 | static int pid_smaps_open(struct inode *inode, struct file *file) |
490 | { | 555 | { |
491 | return do_maps_open(inode, file, &proc_pid_smaps_op); | 556 | return do_maps_open(inode, file, &proc_pid_smaps_op); |
492 | } | 557 | } |
493 | 558 | ||
494 | const struct file_operations proc_smaps_operations = { | 559 | static int tid_smaps_open(struct inode *inode, struct file *file) |
495 | .open = smaps_open, | 560 | { |
561 | return do_maps_open(inode, file, &proc_tid_smaps_op); | ||
562 | } | ||
563 | |||
564 | const struct file_operations proc_pid_smaps_operations = { | ||
565 | .open = pid_smaps_open, | ||
566 | .read = seq_read, | ||
567 | .llseek = seq_lseek, | ||
568 | .release = seq_release_private, | ||
569 | }; | ||
570 | |||
571 | const struct file_operations proc_tid_smaps_operations = { | ||
572 | .open = tid_smaps_open, | ||
496 | .read = seq_read, | 573 | .read = seq_read, |
497 | .llseek = seq_lseek, | 574 | .llseek = seq_lseek, |
498 | .release = seq_release_private, | 575 | .release = seq_release_private, |
@@ -507,6 +584,8 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr, | |||
507 | struct page *page; | 584 | struct page *page; |
508 | 585 | ||
509 | split_huge_page_pmd(walk->mm, pmd); | 586 | split_huge_page_pmd(walk->mm, pmd); |
587 | if (pmd_trans_unstable(pmd)) | ||
588 | return 0; | ||
510 | 589 | ||
511 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); | 590 | pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl); |
512 | for (; addr != end; pte++, addr += PAGE_SIZE) { | 591 | for (; addr != end; pte++, addr += PAGE_SIZE) { |
@@ -598,11 +677,18 @@ const struct file_operations proc_clear_refs_operations = { | |||
598 | .llseek = noop_llseek, | 677 | .llseek = noop_llseek, |
599 | }; | 678 | }; |
600 | 679 | ||
680 | typedef struct { | ||
681 | u64 pme; | ||
682 | } pagemap_entry_t; | ||
683 | |||
601 | struct pagemapread { | 684 | struct pagemapread { |
602 | int pos, len; | 685 | int pos, len; |
603 | u64 *buffer; | 686 | pagemap_entry_t *buffer; |
604 | }; | 687 | }; |
605 | 688 | ||
689 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) | ||
690 | #define PAGEMAP_WALK_MASK (PMD_MASK) | ||
691 | |||
606 | #define PM_ENTRY_BYTES sizeof(u64) | 692 | #define PM_ENTRY_BYTES sizeof(u64) |
607 | #define PM_STATUS_BITS 3 | 693 | #define PM_STATUS_BITS 3 |
608 | #define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) | 694 | #define PM_STATUS_OFFSET (64 - PM_STATUS_BITS) |
@@ -620,10 +706,15 @@ struct pagemapread { | |||
620 | #define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) | 706 | #define PM_NOT_PRESENT PM_PSHIFT(PAGE_SHIFT) |
621 | #define PM_END_OF_BUFFER 1 | 707 | #define PM_END_OF_BUFFER 1 |
622 | 708 | ||
623 | static int add_to_pagemap(unsigned long addr, u64 pfn, | 709 | static inline pagemap_entry_t make_pme(u64 val) |
710 | { | ||
711 | return (pagemap_entry_t) { .pme = val }; | ||
712 | } | ||
713 | |||
714 | static int add_to_pagemap(unsigned long addr, pagemap_entry_t *pme, | ||
624 | struct pagemapread *pm) | 715 | struct pagemapread *pm) |
625 | { | 716 | { |
626 | pm->buffer[pm->pos++] = pfn; | 717 | pm->buffer[pm->pos++] = *pme; |
627 | if (pm->pos >= pm->len) | 718 | if (pm->pos >= pm->len) |
628 | return PM_END_OF_BUFFER; | 719 | return PM_END_OF_BUFFER; |
629 | return 0; | 720 | return 0; |
@@ -635,8 +726,10 @@ static int pagemap_pte_hole(unsigned long start, unsigned long end, | |||
635 | struct pagemapread *pm = walk->private; | 726 | struct pagemapread *pm = walk->private; |
636 | unsigned long addr; | 727 | unsigned long addr; |
637 | int err = 0; | 728 | int err = 0; |
729 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); | ||
730 | |||
638 | for (addr = start; addr < end; addr += PAGE_SIZE) { | 731 | for (addr = start; addr < end; addr += PAGE_SIZE) { |
639 | err = add_to_pagemap(addr, PM_NOT_PRESENT, pm); | 732 | err = add_to_pagemap(addr, &pme, pm); |
640 | if (err) | 733 | if (err) |
641 | break; | 734 | break; |
642 | } | 735 | } |
@@ -649,17 +742,35 @@ static u64 swap_pte_to_pagemap_entry(pte_t pte) | |||
649 | return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); | 742 | return swp_type(e) | (swp_offset(e) << MAX_SWAPFILES_SHIFT); |
650 | } | 743 | } |
651 | 744 | ||
652 | static u64 pte_to_pagemap_entry(pte_t pte) | 745 | static void pte_to_pagemap_entry(pagemap_entry_t *pme, pte_t pte) |
653 | { | 746 | { |
654 | u64 pme = 0; | ||
655 | if (is_swap_pte(pte)) | 747 | if (is_swap_pte(pte)) |
656 | pme = PM_PFRAME(swap_pte_to_pagemap_entry(pte)) | 748 | *pme = make_pme(PM_PFRAME(swap_pte_to_pagemap_entry(pte)) |
657 | | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP; | 749 | | PM_PSHIFT(PAGE_SHIFT) | PM_SWAP); |
658 | else if (pte_present(pte)) | 750 | else if (pte_present(pte)) |
659 | pme = PM_PFRAME(pte_pfn(pte)) | 751 | *pme = make_pme(PM_PFRAME(pte_pfn(pte)) |
660 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; | 752 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); |
661 | return pme; | 753 | } |
754 | |||
755 | #ifdef CONFIG_TRANSPARENT_HUGEPAGE | ||
756 | static void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, | ||
757 | pmd_t pmd, int offset) | ||
758 | { | ||
759 | /* | ||
760 | * Currently pmd for thp is always present because thp can not be | ||
761 | * swapped-out, migrated, or HWPOISONed (split in such cases instead.) | ||
762 | * This if-check is just to prepare for future implementation. | ||
763 | */ | ||
764 | if (pmd_present(pmd)) | ||
765 | *pme = make_pme(PM_PFRAME(pmd_pfn(pmd) + offset) | ||
766 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); | ||
662 | } | 767 | } |
768 | #else | ||
769 | static inline void thp_pmd_to_pagemap_entry(pagemap_entry_t *pme, | ||
770 | pmd_t pmd, int offset) | ||
771 | { | ||
772 | } | ||
773 | #endif | ||
663 | 774 | ||
664 | static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | 775 | static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, |
665 | struct mm_walk *walk) | 776 | struct mm_walk *walk) |
@@ -668,13 +779,30 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
668 | struct pagemapread *pm = walk->private; | 779 | struct pagemapread *pm = walk->private; |
669 | pte_t *pte; | 780 | pte_t *pte; |
670 | int err = 0; | 781 | int err = 0; |
782 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); | ||
671 | 783 | ||
672 | split_huge_page_pmd(walk->mm, pmd); | 784 | if (pmd_trans_unstable(pmd)) |
785 | return 0; | ||
673 | 786 | ||
674 | /* find the first VMA at or above 'addr' */ | 787 | /* find the first VMA at or above 'addr' */ |
675 | vma = find_vma(walk->mm, addr); | 788 | vma = find_vma(walk->mm, addr); |
789 | spin_lock(&walk->mm->page_table_lock); | ||
790 | if (pmd_trans_huge_lock(pmd, vma) == 1) { | ||
791 | for (; addr != end; addr += PAGE_SIZE) { | ||
792 | unsigned long offset; | ||
793 | |||
794 | offset = (addr & ~PAGEMAP_WALK_MASK) >> | ||
795 | PAGE_SHIFT; | ||
796 | thp_pmd_to_pagemap_entry(&pme, *pmd, offset); | ||
797 | err = add_to_pagemap(addr, &pme, pm); | ||
798 | if (err) | ||
799 | break; | ||
800 | } | ||
801 | spin_unlock(&walk->mm->page_table_lock); | ||
802 | return err; | ||
803 | } | ||
804 | |||
676 | for (; addr != end; addr += PAGE_SIZE) { | 805 | for (; addr != end; addr += PAGE_SIZE) { |
677 | u64 pfn = PM_NOT_PRESENT; | ||
678 | 806 | ||
679 | /* check to see if we've left 'vma' behind | 807 | /* check to see if we've left 'vma' behind |
680 | * and need a new, higher one */ | 808 | * and need a new, higher one */ |
@@ -686,11 +814,11 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
686 | if (vma && (vma->vm_start <= addr) && | 814 | if (vma && (vma->vm_start <= addr) && |
687 | !is_vm_hugetlb_page(vma)) { | 815 | !is_vm_hugetlb_page(vma)) { |
688 | pte = pte_offset_map(pmd, addr); | 816 | pte = pte_offset_map(pmd, addr); |
689 | pfn = pte_to_pagemap_entry(*pte); | 817 | pte_to_pagemap_entry(&pme, *pte); |
690 | /* unmap before userspace copy */ | 818 | /* unmap before userspace copy */ |
691 | pte_unmap(pte); | 819 | pte_unmap(pte); |
692 | } | 820 | } |
693 | err = add_to_pagemap(addr, pfn, pm); | 821 | err = add_to_pagemap(addr, &pme, pm); |
694 | if (err) | 822 | if (err) |
695 | return err; | 823 | return err; |
696 | } | 824 | } |
@@ -701,13 +829,12 @@ static int pagemap_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end, | |||
701 | } | 829 | } |
702 | 830 | ||
703 | #ifdef CONFIG_HUGETLB_PAGE | 831 | #ifdef CONFIG_HUGETLB_PAGE |
704 | static u64 huge_pte_to_pagemap_entry(pte_t pte, int offset) | 832 | static void huge_pte_to_pagemap_entry(pagemap_entry_t *pme, |
833 | pte_t pte, int offset) | ||
705 | { | 834 | { |
706 | u64 pme = 0; | ||
707 | if (pte_present(pte)) | 835 | if (pte_present(pte)) |
708 | pme = PM_PFRAME(pte_pfn(pte) + offset) | 836 | *pme = make_pme(PM_PFRAME(pte_pfn(pte) + offset) |
709 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT; | 837 | | PM_PSHIFT(PAGE_SHIFT) | PM_PRESENT); |
710 | return pme; | ||
711 | } | 838 | } |
712 | 839 | ||
713 | /* This function walks within one hugetlb entry in the single call */ | 840 | /* This function walks within one hugetlb entry in the single call */ |
@@ -717,12 +844,12 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | |||
717 | { | 844 | { |
718 | struct pagemapread *pm = walk->private; | 845 | struct pagemapread *pm = walk->private; |
719 | int err = 0; | 846 | int err = 0; |
720 | u64 pfn; | 847 | pagemap_entry_t pme = make_pme(PM_NOT_PRESENT); |
721 | 848 | ||
722 | for (; addr != end; addr += PAGE_SIZE) { | 849 | for (; addr != end; addr += PAGE_SIZE) { |
723 | int offset = (addr & ~hmask) >> PAGE_SHIFT; | 850 | int offset = (addr & ~hmask) >> PAGE_SHIFT; |
724 | pfn = huge_pte_to_pagemap_entry(*pte, offset); | 851 | huge_pte_to_pagemap_entry(&pme, *pte, offset); |
725 | err = add_to_pagemap(addr, pfn, pm); | 852 | err = add_to_pagemap(addr, &pme, pm); |
726 | if (err) | 853 | if (err) |
727 | return err; | 854 | return err; |
728 | } | 855 | } |
@@ -757,8 +884,6 @@ static int pagemap_hugetlb_range(pte_t *pte, unsigned long hmask, | |||
757 | * determine which areas of memory are actually mapped and llseek to | 884 | * determine which areas of memory are actually mapped and llseek to |
758 | * skip over unmapped regions. | 885 | * skip over unmapped regions. |
759 | */ | 886 | */ |
760 | #define PAGEMAP_WALK_SIZE (PMD_SIZE) | ||
761 | #define PAGEMAP_WALK_MASK (PMD_MASK) | ||
762 | static ssize_t pagemap_read(struct file *file, char __user *buf, | 887 | static ssize_t pagemap_read(struct file *file, char __user *buf, |
763 | size_t count, loff_t *ppos) | 888 | size_t count, loff_t *ppos) |
764 | { | 889 | { |
@@ -941,26 +1066,21 @@ static int gather_pte_stats(pmd_t *pmd, unsigned long addr, | |||
941 | pte_t *pte; | 1066 | pte_t *pte; |
942 | 1067 | ||
943 | md = walk->private; | 1068 | md = walk->private; |
944 | spin_lock(&walk->mm->page_table_lock); | 1069 | |
945 | if (pmd_trans_huge(*pmd)) { | 1070 | if (pmd_trans_huge_lock(pmd, md->vma) == 1) { |
946 | if (pmd_trans_splitting(*pmd)) { | 1071 | pte_t huge_pte = *(pte_t *)pmd; |
947 | spin_unlock(&walk->mm->page_table_lock); | 1072 | struct page *page; |
948 | wait_split_huge_page(md->vma->anon_vma, pmd); | 1073 | |
949 | } else { | 1074 | page = can_gather_numa_stats(huge_pte, md->vma, addr); |
950 | pte_t huge_pte = *(pte_t *)pmd; | 1075 | if (page) |
951 | struct page *page; | 1076 | gather_stats(page, md, pte_dirty(huge_pte), |
952 | 1077 | HPAGE_PMD_SIZE/PAGE_SIZE); | |
953 | page = can_gather_numa_stats(huge_pte, md->vma, addr); | ||
954 | if (page) | ||
955 | gather_stats(page, md, pte_dirty(huge_pte), | ||
956 | HPAGE_PMD_SIZE/PAGE_SIZE); | ||
957 | spin_unlock(&walk->mm->page_table_lock); | ||
958 | return 0; | ||
959 | } | ||
960 | } else { | ||
961 | spin_unlock(&walk->mm->page_table_lock); | 1078 | spin_unlock(&walk->mm->page_table_lock); |
1079 | return 0; | ||
962 | } | 1080 | } |
963 | 1081 | ||
1082 | if (pmd_trans_unstable(pmd)) | ||
1083 | return 0; | ||
964 | orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); | 1084 | orig_pte = pte = pte_offset_map_lock(walk->mm, pmd, addr, &ptl); |
965 | do { | 1085 | do { |
966 | struct page *page = can_gather_numa_stats(*pte, md->vma, addr); | 1086 | struct page *page = can_gather_numa_stats(*pte, md->vma, addr); |
@@ -1002,7 +1122,7 @@ static int gather_hugetbl_stats(pte_t *pte, unsigned long hmask, | |||
1002 | /* | 1122 | /* |
1003 | * Display pages allocated per node and memory policy via /proc. | 1123 | * Display pages allocated per node and memory policy via /proc. |
1004 | */ | 1124 | */ |
1005 | static int show_numa_map(struct seq_file *m, void *v) | 1125 | static int show_numa_map(struct seq_file *m, void *v, int is_pid) |
1006 | { | 1126 | { |
1007 | struct numa_maps_private *numa_priv = m->private; | 1127 | struct numa_maps_private *numa_priv = m->private; |
1008 | struct proc_maps_private *proc_priv = &numa_priv->proc_maps; | 1128 | struct proc_maps_private *proc_priv = &numa_priv->proc_maps; |
@@ -1039,9 +1159,19 @@ static int show_numa_map(struct seq_file *m, void *v) | |||
1039 | seq_path(m, &file->f_path, "\n\t= "); | 1159 | seq_path(m, &file->f_path, "\n\t= "); |
1040 | } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { | 1160 | } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { |
1041 | seq_printf(m, " heap"); | 1161 | seq_printf(m, " heap"); |
1042 | } else if (vma->vm_start <= mm->start_stack && | 1162 | } else { |
1043 | vma->vm_end >= mm->start_stack) { | 1163 | pid_t tid = vm_is_stack(proc_priv->task, vma, is_pid); |
1044 | seq_printf(m, " stack"); | 1164 | if (tid != 0) { |
1165 | /* | ||
1166 | * Thread stack in /proc/PID/task/TID/maps or | ||
1167 | * the main process stack. | ||
1168 | */ | ||
1169 | if (!is_pid || (vma->vm_start <= mm->start_stack && | ||
1170 | vma->vm_end >= mm->start_stack)) | ||
1171 | seq_printf(m, " stack"); | ||
1172 | else | ||
1173 | seq_printf(m, " stack:%d", tid); | ||
1174 | } | ||
1045 | } | 1175 | } |
1046 | 1176 | ||
1047 | if (is_vm_hugetlb_page(vma)) | 1177 | if (is_vm_hugetlb_page(vma)) |
@@ -1084,21 +1214,39 @@ out: | |||
1084 | return 0; | 1214 | return 0; |
1085 | } | 1215 | } |
1086 | 1216 | ||
1217 | static int show_pid_numa_map(struct seq_file *m, void *v) | ||
1218 | { | ||
1219 | return show_numa_map(m, v, 1); | ||
1220 | } | ||
1221 | |||
1222 | static int show_tid_numa_map(struct seq_file *m, void *v) | ||
1223 | { | ||
1224 | return show_numa_map(m, v, 0); | ||
1225 | } | ||
1226 | |||
1087 | static const struct seq_operations proc_pid_numa_maps_op = { | 1227 | static const struct seq_operations proc_pid_numa_maps_op = { |
1088 | .start = m_start, | 1228 | .start = m_start, |
1089 | .next = m_next, | 1229 | .next = m_next, |
1090 | .stop = m_stop, | 1230 | .stop = m_stop, |
1091 | .show = show_numa_map, | 1231 | .show = show_pid_numa_map, |
1232 | }; | ||
1233 | |||
1234 | static const struct seq_operations proc_tid_numa_maps_op = { | ||
1235 | .start = m_start, | ||
1236 | .next = m_next, | ||
1237 | .stop = m_stop, | ||
1238 | .show = show_tid_numa_map, | ||
1092 | }; | 1239 | }; |
1093 | 1240 | ||
1094 | static int numa_maps_open(struct inode *inode, struct file *file) | 1241 | static int numa_maps_open(struct inode *inode, struct file *file, |
1242 | const struct seq_operations *ops) | ||
1095 | { | 1243 | { |
1096 | struct numa_maps_private *priv; | 1244 | struct numa_maps_private *priv; |
1097 | int ret = -ENOMEM; | 1245 | int ret = -ENOMEM; |
1098 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | 1246 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); |
1099 | if (priv) { | 1247 | if (priv) { |
1100 | priv->proc_maps.pid = proc_pid(inode); | 1248 | priv->proc_maps.pid = proc_pid(inode); |
1101 | ret = seq_open(file, &proc_pid_numa_maps_op); | 1249 | ret = seq_open(file, ops); |
1102 | if (!ret) { | 1250 | if (!ret) { |
1103 | struct seq_file *m = file->private_data; | 1251 | struct seq_file *m = file->private_data; |
1104 | m->private = priv; | 1252 | m->private = priv; |
@@ -1109,8 +1257,25 @@ static int numa_maps_open(struct inode *inode, struct file *file) | |||
1109 | return ret; | 1257 | return ret; |
1110 | } | 1258 | } |
1111 | 1259 | ||
1112 | const struct file_operations proc_numa_maps_operations = { | 1260 | static int pid_numa_maps_open(struct inode *inode, struct file *file) |
1113 | .open = numa_maps_open, | 1261 | { |
1262 | return numa_maps_open(inode, file, &proc_pid_numa_maps_op); | ||
1263 | } | ||
1264 | |||
1265 | static int tid_numa_maps_open(struct inode *inode, struct file *file) | ||
1266 | { | ||
1267 | return numa_maps_open(inode, file, &proc_tid_numa_maps_op); | ||
1268 | } | ||
1269 | |||
1270 | const struct file_operations proc_pid_numa_maps_operations = { | ||
1271 | .open = pid_numa_maps_open, | ||
1272 | .read = seq_read, | ||
1273 | .llseek = seq_lseek, | ||
1274 | .release = seq_release_private, | ||
1275 | }; | ||
1276 | |||
1277 | const struct file_operations proc_tid_numa_maps_operations = { | ||
1278 | .open = tid_numa_maps_open, | ||
1114 | .read = seq_read, | 1279 | .read = seq_read, |
1115 | .llseek = seq_lseek, | 1280 | .llseek = seq_lseek, |
1116 | .release = seq_release_private, | 1281 | .release = seq_release_private, |