Skip to content

Commit

Permalink
mm: fix false-positive warning on exit due mm_nr_pmds(mm)
Browse files Browse the repository at this point in the history
The problem is that we check nr_ptes/nr_pmds in exit_mmap() which happens
*before* pgd_free().  And if an arch does pte/pmd allocation in
pgd_alloc() and frees them in pgd_free() we see offset in counters by the
time of the checks.

We tried to workaround this by offsetting expected counter value according
to FIRST_USER_ADDRESS for both nr_pte and nr_pmd in exit_mmap().  But it
doesn't work in some cases:

1. ARM with LPAE enabled also has non-zero USER_PGTABLES_CEILING, but
   upper addresses occupied with huge pmd entries, so the trick with
   offsetting expected counter value will get really ugly: we will have
   to apply it nr_pmds, but not nr_ptes.

2. Metag has non-zero FIRST_USER_ADDRESS, but doesn't do allocation
   pte/pmd page tables allocation in pgd_alloc(), just setup a pgd entry
   which is allocated at boot and shared accross all processes.

The proposal is to move the check to check_mm() which happens *after*
pgd_free() and do proper accounting during pgd_alloc() and pgd_free()
which would bring counters to zero if nothing leaked.

Signed-off-by: Kirill A. Shutemov <[email protected]>
Reported-by: Tyler Baker <[email protected]>
Tested-by: Tyler Baker <[email protected]>
Tested-by: Nishanth Menon <[email protected]>
Cc: Russell King <[email protected]>
Cc: James Hogan <[email protected]>
Cc: Guan Xuetao <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
kiryl authored and torvalds committed Feb 12, 2015
1 parent dc6c9a3 commit b30fe6c
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 5 deletions.
4 changes: 4 additions & 0 deletions arch/arm/mm/pgd.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pgd_t *pgd_alloc(struct mm_struct *mm)

no_pte:
pmd_free(mm, new_pmd);
mm_dec_nr_pmds(mm);
no_pmd:
pud_free(mm, new_pud);
no_pud:
Expand Down Expand Up @@ -130,9 +131,11 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
pte = pmd_pgtable(*pmd);
pmd_clear(pmd);
pte_free(mm, pte);
atomic_long_dec(&mm->nr_ptes);
no_pmd:
pud_clear(pud);
pmd_free(mm, pmd);
mm_dec_nr_pmds(mm);
no_pud:
pgd_clear(pgd);
pud_free(mm, pud);
Expand All @@ -152,6 +155,7 @@ void pgd_free(struct mm_struct *mm, pgd_t *pgd_base)
pmd = pmd_offset(pud, 0);
pud_clear(pud);
pmd_free(mm, pmd);
mm_dec_nr_pmds(mm);
pgd_clear(pgd);
pud_free(mm, pud);
}
Expand Down
3 changes: 3 additions & 0 deletions arch/unicore32/mm/pgd.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)

no_pte:
pmd_free(mm, new_pmd);
mm_dec_nr_pmds(mm);
no_pmd:
free_pages((unsigned long)new_pgd, 0);
no_pgd:
Expand Down Expand Up @@ -96,7 +97,9 @@ void free_pgd_slow(struct mm_struct *mm, pgd_t *pgd)
pte = pmd_pgtable(*pmd);
pmd_clear(pmd);
pte_free(mm, pte);
atomic_long_dec(&mm->nr_ptes);
pmd_free(mm, pmd);
mm_dec_nr_pmds(mm);
free:
free_pages((unsigned long) pgd, 0);
}
8 changes: 8 additions & 0 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,14 @@ static void check_mm(struct mm_struct *mm)
printk(KERN_ALERT "BUG: Bad rss-counter state "
"mm:%p idx:%d val:%ld\n", mm, i, x);
}

if (atomic_long_read(&mm->nr_ptes))
pr_alert("BUG: non-zero nr_ptes on freeing mm: %ld\n",
atomic_long_read(&mm->nr_ptes));
if (mm_nr_pmds(mm))
pr_alert("BUG: non-zero nr_pmds on freeing mm: %ld\n",
mm_nr_pmds(mm));

#if defined(CONFIG_TRANSPARENT_HUGEPAGE) && !USE_SPLIT_PMD_PTLOCKS
VM_BUG_ON_MM(mm->pmd_huge_pte, mm);
#endif
Expand Down
5 changes: 0 additions & 5 deletions mm/mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2851,11 +2851,6 @@ void exit_mmap(struct mm_struct *mm)
vma = remove_vma(vma);
}
vm_unacct_memory(nr_accounted);

WARN_ON(atomic_long_read(&mm->nr_ptes) >
round_up(FIRST_USER_ADDRESS, PMD_SIZE) >> PMD_SHIFT);
WARN_ON(mm_nr_pmds(mm) >
round_up(FIRST_USER_ADDRESS, PUD_SIZE) >> PUD_SHIFT);
}

/* Insert vm structure into process list sorted by address
Expand Down

0 comments on commit b30fe6c

Please sign in to comment.