aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/proc.txt18
-rw-r--r--fs/proc/task_mmu.c18
-rw-r--r--include/linux/swap.h6
-rw-r--r--mm/swapfile.c42
4 files changed, 77 insertions, 7 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 6f7fafde0884..d411ca63c8b6 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -424,6 +424,7 @@ Private_Dirty: 0 kB
424Referenced: 892 kB 424Referenced: 892 kB
425Anonymous: 0 kB 425Anonymous: 0 kB
426Swap: 0 kB 426Swap: 0 kB
427SwapPss: 0 kB
427KernelPageSize: 4 kB 428KernelPageSize: 4 kB
428MMUPageSize: 4 kB 429MMUPageSize: 4 kB
429Locked: 374 kB 430Locked: 374 kB
@@ -433,16 +434,23 @@ the first of these lines shows the same information as is displayed for the
433mapping in /proc/PID/maps. The remaining lines show the size of the mapping 434mapping in /proc/PID/maps. The remaining lines show the size of the mapping
434(size), the amount of the mapping that is currently resident in RAM (RSS), the 435(size), the amount of the mapping that is currently resident in RAM (RSS), the
435process' proportional share of this mapping (PSS), the number of clean and 436process' proportional share of this mapping (PSS), the number of clean and
436dirty private pages in the mapping. Note that even a page which is part of a 437dirty private pages in the mapping.
437MAP_SHARED mapping, but has only a single pte mapped, i.e. is currently used 438
438by only one process, is accounted as private and not as shared. "Referenced" 439The "proportional set size" (PSS) of a process is the count of pages it has
439indicates the amount of memory currently marked as referenced or accessed. 440in memory, where each page is divided by the number of processes sharing it.
441So if a process has 1000 pages all to itself, and 1000 shared with one other
442process, its PSS will be 1500.
443Note that even a page which is part of a MAP_SHARED mapping, but has only
444a single pte mapped, i.e. is currently used by only one process, is accounted
445as private and not as shared.
446"Referenced" indicates the amount of memory currently marked as referenced or
447accessed.
440"Anonymous" shows the amount of memory that does not belong to any file. Even 448"Anonymous" shows the amount of memory that does not belong to any file. Even
441a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE 449a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
442and a page is modified, the file page is replaced by a private anonymous copy. 450and a page is modified, the file page is replaced by a private anonymous copy.
443"Swap" shows how much would-be-anonymous memory is also used, but out on 451"Swap" shows how much would-be-anonymous memory is also used, but out on
444swap. 452swap.
445 453"SwapPss" shows proportional swap share of this mapping.
446"VmFlags" field deserves a separate description. This member represents the kernel 454"VmFlags" field deserves a separate description. This member represents the kernel
447flags associated with the particular virtual memory area in two letter encoded 455flags associated with the particular virtual memory area in two letter encoded
448manner. The codes are the following: 456manner. The codes are the following:
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 67c76468a7be..41f1a50c10c9 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -446,6 +446,7 @@ struct mem_size_stats {
446 unsigned long anonymous_thp; 446 unsigned long anonymous_thp;
447 unsigned long swap; 447 unsigned long swap;
448 u64 pss; 448 u64 pss;
449 u64 swap_pss;
449}; 450};
450 451
451static void smaps_account(struct mem_size_stats *mss, struct page *page, 452static void smaps_account(struct mem_size_stats *mss, struct page *page,
@@ -492,9 +493,20 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
492 } else if (is_swap_pte(*pte)) { 493 } else if (is_swap_pte(*pte)) {
493 swp_entry_t swpent = pte_to_swp_entry(*pte); 494 swp_entry_t swpent = pte_to_swp_entry(*pte);
494 495
495 if (!non_swap_entry(swpent)) 496 if (!non_swap_entry(swpent)) {
497 int mapcount;
498
496 mss->swap += PAGE_SIZE; 499 mss->swap += PAGE_SIZE;
497 else if (is_migration_entry(swpent)) 500 mapcount = swp_swapcount(swpent);
501 if (mapcount >= 2) {
502 u64 pss_delta = (u64)PAGE_SIZE << PSS_SHIFT;
503
504 do_div(pss_delta, mapcount);
505 mss->swap_pss += pss_delta;
506 } else {
507 mss->swap_pss += (u64)PAGE_SIZE << PSS_SHIFT;
508 }
509 } else if (is_migration_entry(swpent))
498 page = migration_entry_to_page(swpent); 510 page = migration_entry_to_page(swpent);
499 } 511 }
500 512
@@ -640,6 +652,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
640 "Anonymous: %8lu kB\n" 652 "Anonymous: %8lu kB\n"
641 "AnonHugePages: %8lu kB\n" 653 "AnonHugePages: %8lu kB\n"
642 "Swap: %8lu kB\n" 654 "Swap: %8lu kB\n"
655 "SwapPss: %8lu kB\n"
643 "KernelPageSize: %8lu kB\n" 656 "KernelPageSize: %8lu kB\n"
644 "MMUPageSize: %8lu kB\n" 657 "MMUPageSize: %8lu kB\n"
645 "Locked: %8lu kB\n", 658 "Locked: %8lu kB\n",
@@ -654,6 +667,7 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
654 mss.anonymous >> 10, 667 mss.anonymous >> 10,
655 mss.anonymous_thp >> 10, 668 mss.anonymous_thp >> 10,
656 mss.swap >> 10, 669 mss.swap >> 10,
670 (unsigned long)(mss.swap_pss >> (10 + PSS_SHIFT)),
657 vma_kernel_pagesize(vma) >> 10, 671 vma_kernel_pagesize(vma) >> 10,
658 vma_mmu_pagesize(vma) >> 10, 672 vma_mmu_pagesize(vma) >> 10,
659 (vma->vm_flags & VM_LOCKED) ? 673 (vma->vm_flags & VM_LOCKED) ?
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 31496d201fdc..6282f1eb3d6a 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -431,6 +431,7 @@ extern unsigned int count_swap_pages(int, int);
431extern sector_t map_swap_page(struct page *, struct block_device **); 431extern sector_t map_swap_page(struct page *, struct block_device **);
432extern sector_t swapdev_block(int, pgoff_t); 432extern sector_t swapdev_block(int, pgoff_t);
433extern int page_swapcount(struct page *); 433extern int page_swapcount(struct page *);
434extern int swp_swapcount(swp_entry_t entry);
434extern struct swap_info_struct *page_swap_info(struct page *); 435extern struct swap_info_struct *page_swap_info(struct page *);
435extern int reuse_swap_page(struct page *); 436extern int reuse_swap_page(struct page *);
436extern int try_to_free_swap(struct page *); 437extern int try_to_free_swap(struct page *);
@@ -522,6 +523,11 @@ static inline int page_swapcount(struct page *page)
522 return 0; 523 return 0;
523} 524}
524 525
526static inline int swp_swapcount(swp_entry_t entry)
527{
528 return 0;
529}
530
525#define reuse_swap_page(page) (page_mapcount(page) == 1) 531#define reuse_swap_page(page) (page_mapcount(page) == 1)
526 532
527static inline int try_to_free_swap(struct page *page) 533static inline int try_to_free_swap(struct page *page)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index aebc2dd6e649..58877312cf6b 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -875,6 +875,48 @@ int page_swapcount(struct page *page)
875} 875}
876 876
877/* 877/*
878 * How many references to @entry are currently swapped out?
879 * This considers COUNT_CONTINUED so it returns exact answer.
880 */
881int swp_swapcount(swp_entry_t entry)
882{
883 int count, tmp_count, n;
884 struct swap_info_struct *p;
885 struct page *page;
886 pgoff_t offset;
887 unsigned char *map;
888
889 p = swap_info_get(entry);
890 if (!p)
891 return 0;
892
893 count = swap_count(p->swap_map[swp_offset(entry)]);
894 if (!(count & COUNT_CONTINUED))
895 goto out;
896
897 count &= ~COUNT_CONTINUED;
898 n = SWAP_MAP_MAX + 1;
899
900 offset = swp_offset(entry);
901 page = vmalloc_to_page(p->swap_map + offset);
902 offset &= ~PAGE_MASK;
903 VM_BUG_ON(page_private(page) != SWP_CONTINUED);
904
905 do {
906 page = list_entry(page->lru.next, struct page, lru);
907 map = kmap_atomic(page);
908 tmp_count = map[offset];
909 kunmap_atomic(map);
910
911 count += (tmp_count & ~COUNT_CONTINUED) * n;
912 n *= (SWAP_CONT_MAX + 1);
913 } while (tmp_count & COUNT_CONTINUED);
914out:
915 spin_unlock(&p->lock);
916 return count;
917}
918
919/*
878 * We can write to an anon page without COW if there are no other references 920 * We can write to an anon page without COW if there are no other references
879 * to it. And as a side-effect, free up its swap: because the old content 921 * to it. And as a side-effect, free up its swap: because the old content
880 * on disk will never be read, and seeking back there to write new content 922 * on disk will never be read, and seeking back there to write new content