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 <jmarc...@redhat.com>
---
 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 from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to