[PATCH] smaps: fix dirty pages accounting

KOSAKI Motohiro
2010-09-16T06:34:39Z

Currently, /proc/<pid>/smaps have wrong dirty pages accounting.
Shared_Dirty and Private_Dirty output only pte dirty pages and
ignore PG_dirty page flag. It is difference against documentation,
but also inconsistent against Referenced field. (Referenced checks
both pte and page flags)

This patch fixes it.

Test program:

large-array.c
---------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

char array[1*1024*1024*1024L];

int main(void)
{
memset(array, 1, sizeof(array));
pause();

return 0;
}
---------------------------------------------------

Test case:
1. run ./large-array
2. cat /proc/`pidof large-array`/smaps
3. swapoff -a
4. cat /proc/`pidof large-array`/smaps again

Test result:
<before patch>

00601000-40601000 rw-p 00000000 00:00 0
Size: 1048576 kB
Rss: 1048576 kB
Pss: 1048576 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 218992 kB <-- showed pages as clean incorrectly
Private_Dirty: 829584 kB
Referenced: 388364 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB

<after patch>

00601000-40601000 rw-p 00000000 00:00 0
Size: 1048576 kB
Rss: 1048576 kB
Pss: 1048576 kB
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 1048576 kB <-- fixed
Referenced: 388480 kB
Swap: 0 kB
KernelPageSize: 4 kB
MMUPageSize: 4 kB

Signed-off-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
---
fs/proc/task_mmu.c | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 439fc1f..7415f13 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -362,13 +362,13 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
mss->referenced += PAGE_SIZE;
mapcount = page_mapcount(page);
if (mapcount >= 2) {
- if (pte_dirty(ptent))
+ if (pte_dirty(ptent) || PageDirty(page))
mss->shared_dirty += PAGE_SIZE;
else
mss->shared_clean += PAGE_SIZE;
mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
} else {
- if (pte_dirty(ptent))
+ if (pte_dirty(ptent) || PageDirty(page))
mss->private_dirty += PAGE_SIZE;
else
mss->private_clean += PAGE_SIZE;
--
1.6.5.2