aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/proc/task_mmu.c47
1 files changed, 31 insertions, 16 deletions
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index a353b4c6e86e..b74e7dec37dd 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -466,9 +466,10 @@ struct mem_size_stats {
466}; 466};
467 467
468static void smaps_account(struct mem_size_stats *mss, struct page *page, 468static void smaps_account(struct mem_size_stats *mss, struct page *page,
469 unsigned long size, bool young, bool dirty) 469 bool compound, bool young, bool dirty)
470{ 470{
471 int mapcount; 471 int i, nr = compound ? HPAGE_PMD_NR : 1;
472 unsigned long size = nr * PAGE_SIZE;
472 473
473 if (PageAnon(page)) 474 if (PageAnon(page))
474 mss->anonymous += size; 475 mss->anonymous += size;
@@ -477,23 +478,37 @@ static void smaps_account(struct mem_size_stats *mss, struct page *page,
477 /* Accumulate the size in pages that have been accessed. */ 478 /* Accumulate the size in pages that have been accessed. */
478 if (young || page_is_young(page) || PageReferenced(page)) 479 if (young || page_is_young(page) || PageReferenced(page))
479 mss->referenced += size; 480 mss->referenced += size;
480 mapcount = page_mapcount(page);
481 if (mapcount >= 2) {
482 u64 pss_delta;
483 481
484 if (dirty || PageDirty(page)) 482 /*
485 mss->shared_dirty += size; 483 * page_count(page) == 1 guarantees the page is mapped exactly once.
486 else 484 * If any subpage of the compound page mapped with PTE it would elevate
487 mss->shared_clean += size; 485 * page_count().
488 pss_delta = (u64)size << PSS_SHIFT; 486 */
489 do_div(pss_delta, mapcount); 487 if (page_count(page) == 1) {
490 mss->pss += pss_delta;
491 } else {
492 if (dirty || PageDirty(page)) 488 if (dirty || PageDirty(page))
493 mss->private_dirty += size; 489 mss->private_dirty += size;
494 else 490 else
495 mss->private_clean += size; 491 mss->private_clean += size;
496 mss->pss += (u64)size << PSS_SHIFT; 492 mss->pss += (u64)size << PSS_SHIFT;
493 return;
494 }
495
496 for (i = 0; i < nr; i++, page++) {
497 int mapcount = page_mapcount(page);
498
499 if (mapcount >= 2) {
500 if (dirty || PageDirty(page))
501 mss->shared_dirty += PAGE_SIZE;
502 else
503 mss->shared_clean += PAGE_SIZE;
504 mss->pss += (PAGE_SIZE << PSS_SHIFT) / mapcount;
505 } else {
506 if (dirty || PageDirty(page))
507 mss->private_dirty += PAGE_SIZE;
508 else
509 mss->private_clean += PAGE_SIZE;
510 mss->pss += PAGE_SIZE << PSS_SHIFT;
511 }
497 } 512 }
498} 513}
499 514
@@ -554,7 +569,8 @@ static void smaps_pte_entry(pte_t *pte, unsigned long addr,
554 569
555 if (!page) 570 if (!page)
556 return; 571 return;
557 smaps_account(mss, page, PAGE_SIZE, pte_young(*pte), pte_dirty(*pte)); 572
573 smaps_account(mss, page, false, pte_young(*pte), pte_dirty(*pte));
558} 574}
559 575
560#ifdef CONFIG_TRANSPARENT_HUGEPAGE 576#ifdef CONFIG_TRANSPARENT_HUGEPAGE
@@ -570,8 +586,7 @@ static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
570 if (IS_ERR_OR_NULL(page)) 586 if (IS_ERR_OR_NULL(page))
571 return; 587 return;
572 mss->anonymous_thp += HPAGE_PMD_SIZE; 588 mss->anonymous_thp += HPAGE_PMD_SIZE;
573 smaps_account(mss, page, HPAGE_PMD_SIZE, 589 smaps_account(mss, page, true, pmd_young(*pmd), pmd_dirty(*pmd));
574 pmd_young(*pmd), pmd_dirty(*pmd));
575} 590}
576#else 591#else
577static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr, 592static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,