Adds get_mm_shswap() which compute the size of swaped out shmem. It does so by pagewalking the mm and using the new shmem_locate() function to get the physical location of shmem pages. The result is displayed in the new VmShSw line of /proc/<pid>/status. Use mm_walk an shmem_locate() to account paged out shmem pages. It significantly slows down /proc/<pid>/status acccess speed when there is a big shmem mapping. If that is an issue, we can drop this patch and only display this counter in the inherently slower /proc/<pid>/smaps file (cf. next patch). Signed-off-by: Jerome Marchand <jmarchan@xxxxxxxxxx> --- Documentation/filesystems/proc.txt | 2 + fs/proc/task_mmu.c | 80 ++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 1c49957..1a15c56 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt @@ -172,6 +172,7 @@ read the file /proc/PID/status: VmPTE: 20 kb VmSwap: 0 kB VmShm: 0 kB + VmShSw: 0 kB Threads: 1 SigQ: 0/28578 SigPnd: 0000000000000000 @@ -230,6 +231,7 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7) VmPTE size of page table entries VmSwap size of swap usage (the number of referred swapents) VmShm size of resident shmem memory + VmShSw size of paged out shmem memory Threads number of threads SigQ number of signals queued/max. number for queue SigPnd bitmap of pending signals for the thread diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 4e60751..73f0ce4 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -19,9 +19,80 @@ #include <asm/tlbflush.h> #include "internal.h" +struct shswap_stats { + struct vm_area_struct *vma; + unsigned long shswap; +}; + +#ifdef CONFIG_SHMEM +static int shswap_pte(pte_t *pte, unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct shswap_stats *shss = walk->private; + struct vm_area_struct *vma = shss->vma; + pgoff_t pgoff = linear_page_index(vma, addr); + pte_t ptent = *pte; + + if (pte_none(ptent) && + shmem_locate(vma, pgoff, NULL) == SHMEM_SWAP) + shss->shswap += end - addr; + + return 0; +} + +static int shswap_pte_hole(unsigned long addr, unsigned long end, + struct mm_walk *walk) +{ + struct shswap_stats *shss = walk->private; + struct vm_area_struct *vma = shss->vma; + pgoff_t pgoff; + + for (; addr != end; addr += PAGE_SIZE) { + pgoff = linear_page_index(vma, addr); + + if (shmem_locate(vma, pgoff, NULL) == SHMEM_SWAP) + shss->shswap += PAGE_SIZE; + } + + return 0; +} + +static unsigned long get_mm_shswap(struct mm_struct *mm) +{ + struct vm_area_struct *vma; + struct shswap_stats shss; + struct mm_walk shswap_walk = { + .pte_entry = shswap_pte, + .pte_hole = shswap_pte_hole, + .mm = mm, + .private = &shss, + }; + + memset(&shss, 0, sizeof(shss)); + + down_read(&mm->mmap_sem); + for (vma = mm->mmap; vma; vma = vma->vm_next) + if (shmem_vma(vma)) { + shss.vma = vma; + walk_page_range(vma->vm_start, vma->vm_end, + &shswap_walk); + } + up_read(&mm->mmap_sem); + + return shss.shswap; +} + +#else + +static unsigned long get_mm_shswap(struct mm_struct *mm) +{ + return 0; +} +#endif + void task_mem(struct seq_file *m, struct mm_struct *mm) { - unsigned long data, text, lib, swap, shmem; + unsigned long data, text, lib, swap, shmem, shswap; unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss; /* @@ -43,6 +114,7 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text; swap = get_mm_counter(mm, MM_SWAPENTS); shmem = get_mm_counter(mm, MM_SHMEMPAGES); + shswap = get_mm_shswap(mm); seq_printf(m, "VmPeak:\t%8lu kB\n" "VmSize:\t%8lu kB\n" @@ -56,7 +128,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) "VmLib:\t%8lu kB\n" "VmPTE:\t%8lu kB\n" "VmSwap:\t%8lu kB\n" - "VmShm:\t%8lu kB\n", + "VmShm:\t%8lu kB\n" + "VmShSw:\t%8lu kB\n", hiwater_vm << (PAGE_SHIFT-10), total_vm << (PAGE_SHIFT-10), mm->locked_vm << (PAGE_SHIFT-10), @@ -68,7 +141,8 @@ void task_mem(struct seq_file *m, struct mm_struct *mm) (PTRS_PER_PTE * sizeof(pte_t) * atomic_long_read(&mm->nr_ptes)) >> 10, swap << (PAGE_SHIFT-10), - shmem << (PAGE_SHIFT-10)); + shmem << (PAGE_SHIFT-10), + shswap >> 10); } unsigned long task_vsize(struct mm_struct *mm) -- 1.9.3 -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"dont@xxxxxxxxx"> email@xxxxxxxxx </a>