Commit 8586febd authored by Hugh Dickins's avatar Hugh Dickins Committed by Linus Torvalds

[PATCH] statm: shared = rss - anon_rss

The third "shared" field of /proc/$pid/statm in 2.4 was a count of pages in
the mm whose page_count is more than 1 (oddly, including pages shared just
with swapcache).  That's too costly to calculate each time, so 2.6 changed
it to the total file-backed extent.  But Andrea knows apps and users
surprised when (rss - shared) goes negative: we need to provide an rss-like
statistic, close to the 2.4 interpretation.

Something that's quick and easy to maintain accurately is mm->anon_rss, the
count of anonymous pages in the mm.  Then shared = rss - anon_rss gives a
pretty good and meaningful approximation to 2.4's intention: wli confirms
that this will be useful to Oracle too.

Where to show it?  I think it's best to treat this as a bugfix and show it
in the third field of /proc/$pid/statm, after resident, as before - there's
no evidence that the total file-backed extent was found useful.

Albert would like other fields to revert to page counts, but that's a lot
harder: if mprotect can change the category of a page, then it can't be
accounted as simply as this.  Only go that route if real need shown.
Signed-off-by: default avatarHugh Dickins <hugh@veritas.com>
Acked-by: default avatarWilliam Irwin <wli@holomorphy.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent da63671a
...@@ -37,7 +37,7 @@ unsigned long task_vsize(struct mm_struct *mm) ...@@ -37,7 +37,7 @@ unsigned long task_vsize(struct mm_struct *mm)
int task_statm(struct mm_struct *mm, int *shared, int *text, int task_statm(struct mm_struct *mm, int *shared, int *text,
int *data, int *resident) int *data, int *resident)
{ {
*shared = mm->shared_vm; *shared = mm->rss - mm->anon_rss;
*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) *text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
>> PAGE_SHIFT; >> PAGE_SHIFT;
*data = mm->total_vm - mm->shared_vm - *text; *data = mm->total_vm - mm->shared_vm - *text;
......
...@@ -216,7 +216,7 @@ struct mm_struct { ...@@ -216,7 +216,7 @@ struct mm_struct {
atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */ atomic_t mm_count; /* How many references to "struct mm_struct" (users count as 1) */
int map_count; /* number of VMAs */ int map_count; /* number of VMAs */
struct rw_semaphore mmap_sem; struct rw_semaphore mmap_sem;
spinlock_t page_table_lock; /* Protects task page tables and mm->rss */ spinlock_t page_table_lock; /* Protects page tables, mm->rss, mm->anon_rss */
struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung struct list_head mmlist; /* List of maybe swapped mm's. These are globally strung
* together off init_mm.mmlist, and are protected * together off init_mm.mmlist, and are protected
...@@ -226,7 +226,7 @@ struct mm_struct { ...@@ -226,7 +226,7 @@ struct mm_struct {
unsigned long start_code, end_code, start_data, end_data; unsigned long start_code, end_code, start_data, end_data;
unsigned long start_brk, brk, start_stack; unsigned long start_brk, brk, start_stack;
unsigned long arg_start, arg_end, env_start, env_end; unsigned long arg_start, arg_end, env_start, env_end;
unsigned long rss, total_vm, locked_vm, shared_vm; unsigned long rss, anon_rss, total_vm, locked_vm, shared_vm;
unsigned long exec_vm, stack_vm, reserved_vm, def_flags, nr_ptes; unsigned long exec_vm, stack_vm, reserved_vm, def_flags, nr_ptes;
unsigned long saved_auxv[42]; /* for /proc/PID/auxv */ unsigned long saved_auxv[42]; /* for /proc/PID/auxv */
......
...@@ -173,6 +173,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm) ...@@ -173,6 +173,7 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm)
mm->free_area_cache = oldmm->mmap_base; mm->free_area_cache = oldmm->mmap_base;
mm->map_count = 0; mm->map_count = 0;
mm->rss = 0; mm->rss = 0;
mm->anon_rss = 0;
cpus_clear(mm->cpu_vm_mask); cpus_clear(mm->cpu_vm_mask);
mm->mm_rb = RB_ROOT; mm->mm_rb = RB_ROOT;
rb_link = &mm->mm_rb.rb_node; rb_link = &mm->mm_rb.rb_node;
......
...@@ -334,6 +334,8 @@ skip_copy_pmd_range: address = (address + PGDIR_SIZE) & PGDIR_MASK; ...@@ -334,6 +334,8 @@ skip_copy_pmd_range: address = (address + PGDIR_SIZE) & PGDIR_MASK;
pte = pte_mkold(pte); pte = pte_mkold(pte);
get_page(page); get_page(page);
dst->rss++; dst->rss++;
if (PageAnon(page))
dst->anon_rss++;
set_pte(dst_pte, pte); set_pte(dst_pte, pte);
page_dup_rmap(page); page_dup_rmap(page);
cont_copy_pte_range_noset: cont_copy_pte_range_noset:
...@@ -424,7 +426,9 @@ static void zap_pte_range(struct mmu_gather *tlb, ...@@ -424,7 +426,9 @@ static void zap_pte_range(struct mmu_gather *tlb,
set_pte(ptep, pgoff_to_pte(page->index)); set_pte(ptep, pgoff_to_pte(page->index));
if (pte_dirty(pte)) if (pte_dirty(pte))
set_page_dirty(page); set_page_dirty(page);
if (pte_young(pte) && !PageAnon(page)) if (PageAnon(page))
tlb->mm->anon_rss--;
else if (pte_young(pte))
mark_page_accessed(page); mark_page_accessed(page);
tlb->freed++; tlb->freed++;
page_remove_rmap(page); page_remove_rmap(page);
...@@ -1109,6 +1113,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1109,6 +1113,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
page_table = pte_offset_map(pmd, address); page_table = pte_offset_map(pmd, address);
if (likely(pte_same(*page_table, pte))) { if (likely(pte_same(*page_table, pte))) {
if (PageAnon(old_page))
mm->anon_rss--;
if (PageReserved(old_page)) if (PageReserved(old_page))
++mm->rss; ++mm->rss;
else else
......
...@@ -432,6 +432,8 @@ void page_add_anon_rmap(struct page *page, ...@@ -432,6 +432,8 @@ void page_add_anon_rmap(struct page *page,
BUG_ON(PageReserved(page)); BUG_ON(PageReserved(page));
BUG_ON(!anon_vma); BUG_ON(!anon_vma);
vma->vm_mm->anon_rss++;
anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON; anon_vma = (void *) anon_vma + PAGE_MAPPING_ANON;
index = (address - vma->vm_start) >> PAGE_SHIFT; index = (address - vma->vm_start) >> PAGE_SHIFT;
index += vma->vm_pgoff; index += vma->vm_pgoff;
...@@ -584,6 +586,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma) ...@@ -584,6 +586,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma)
} }
set_pte(pte, swp_entry_to_pte(entry)); set_pte(pte, swp_entry_to_pte(entry));
BUG_ON(pte_file(*pte)); BUG_ON(pte_file(*pte));
mm->anon_rss--;
} }
mm->rss--; mm->rss--;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment