diff options
-rw-r--r-- | Documentation/filesystems/proc.txt | 5 | ||||
-rw-r--r-- | fs/proc/task_mmu.c | 51 |
2 files changed, 55 insertions, 1 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 9f13b6e28676..fdeb5b33349f 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt | |||
@@ -460,7 +460,10 @@ and a page is modified, the file page is replaced by a private anonymous copy. | |||
460 | hugetlbfs page which is *not* counted in "RSS" or "PSS" field for historical | 460 | hugetlbfs page which is *not* counted in "RSS" or "PSS" field for historical |
461 | reasons. And these are not included in {Shared,Private}_{Clean,Dirty} field. | 461 | reasons. And these are not included in {Shared,Private}_{Clean,Dirty} field. |
462 | "Swap" shows how much would-be-anonymous memory is also used, but out on swap. | 462 | "Swap" shows how much would-be-anonymous memory is also used, but out on swap. |
463 | "SwapPss" shows proportional swap share of this mapping. | 463 | For shmem mappings, "Swap" includes also the size of the mapped (and not |
464 | replaced by copy-on-write) part of the underlying shmem object out on swap. | ||
465 | "SwapPss" shows proportional swap share of this mapping. Unlike "Swap", this | ||
466 | does not take into account swapped out page of underlying shmem objects. | ||
464 | "Locked" indicates whether the mapping is locked in memory or not. | 467 | "Locked" indicates whether the mapping is locked in memory or not. |
465 | 468 | ||
466 | "VmFlags" field deserves a separate description. This member represents the kernel | 469 | "VmFlags" field deserves a separate description. This member represents the kernel |
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 187b3b5f242e..85ef60fdf2c0 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c | |||
@@ -451,6 +451,7 @@ struct mem_size_stats { | |||
451 | unsigned long private_hugetlb; | 451 | unsigned long private_hugetlb; |
452 | u64 pss; | 452 | u64 pss; |
453 | u64 swap_pss; | 453 | u64 swap_pss; |
454 | bool check_shmem_swap; | ||
454 | }; | 455 | }; |
455 | 456 | ||
456 | static void smaps_account(struct mem_size_stats *mss, struct page *page, | 457 | static void smaps_account(struct mem_size_stats *mss, struct page *page, |
@@ -485,6 +486,45 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page, | |||
485 | } | 486 | } |
486 | } | 487 | } |
487 | 488 | ||
489 | #ifdef CONFIG_SHMEM | ||
490 | static unsigned long smaps_shmem_swap(struct vm_area_struct *vma, | ||
491 | unsigned long addr) | ||
492 | { | ||
493 | struct page *page; | ||
494 | |||
495 | page = find_get_entry(vma->vm_file->f_mapping, | ||
496 | linear_page_index(vma, addr)); | ||
497 | if (!page) | ||
498 | return 0; | ||
499 | |||
500 | if (radix_tree_exceptional_entry(page)) | ||
501 | return PAGE_SIZE; | ||
502 | |||
503 | page_cache_release(page); | ||
504 | return 0; | ||
505 | |||
506 | } | ||
507 | |||
508 | static int smaps_pte_hole(unsigned long addr, unsigned long end, | ||
509 | struct mm_walk *walk) | ||
510 | { | ||
511 | struct mem_size_stats *mss = walk->private; | ||
512 | |||
513 | while (addr < end) { | ||
514 | mss->swap += smaps_shmem_swap(walk->vma, addr); | ||
515 | addr += PAGE_SIZE; | ||
516 | } | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | #else | ||
521 | static unsigned long smaps_shmem_swap(struct vm_area_struct *vma, | ||
522 | unsigned long addr) | ||
523 | { | ||
524 | return 0; | ||
525 | } | ||
526 | #endif | ||
527 | |||
488 | static void smaps_pte_entry(pte_t *pte, unsigned long addr, | 528 | static void smaps_pte_entry(pte_t *pte, unsigned long addr, |
489 | struct mm_walk *walk) | 529 | struct mm_walk *walk) |
490 | { | 530 | { |
@@ -512,6 +552,9 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr, | |||
512 | } | 552 | } |
513 | } else if (is_migration_entry(swpent)) | 553 | } else if (is_migration_entry(swpent)) |
514 | page = migration_entry_to_page(swpent); | 554 | page = migration_entry_to_page(swpent); |
555 | } else if (unlikely(IS_ENABLED(CONFIG_SHMEM) && mss->check_shmem_swap | ||
556 | && pte_none(*pte))) { | ||
557 | mss->swap += smaps_shmem_swap(vma, addr); | ||
515 | } | 558 | } |
516 | 559 | ||
517 | if (!page) | 560 | if (!page) |
@@ -671,6 +714,14 @@ static int show_smap(struct seq_file *m, void *v, int is_pid) | |||
671 | }; | 714 | }; |
672 | 715 | ||
673 | memset(&mss, 0, sizeof mss); | 716 | memset(&mss, 0, sizeof mss); |
717 | |||
718 | #ifdef CONFIG_SHMEM | ||
719 | if (vma->vm_file && shmem_mapping(vma->vm_file->f_mapping)) { | ||
720 | mss.check_shmem_swap = true; | ||
721 | smaps_walk.pte_hole = smaps_pte_hole; | ||
722 | } | ||
723 | #endif | ||
724 | |||
674 | /* mmap_sem is held in m_start */ | 725 | /* mmap_sem is held in m_start */ |
675 | walk_page_vma(vma, &smaps_walk); | 726 | walk_page_vma(vma, &smaps_walk); |
676 | 727 | ||