mm: fix false-positive warning on exit due mm_nr_pmds(mm)
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 <kirill.shutemov@linux.intel.com> Reported-by: Tyler Baker <tyler.baker@linaro.org> Tested-by: Tyler Baker <tyler.baker@linaro.org> Tested-by: Nishanth Menon <nm@ti.com> Cc: Russell King <linux@arm.linux.org.uk> Cc: James Hogan <james.hogan@imgtec.com> Cc: Guan Xuetao <gxt@mprc.pku.edu.cn> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									dc6c9a35b6
								
							
						
					
					
						commit
						b30fe6c7ce
					
				| @ -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: | ||||
| @ -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); | ||||
| @ -152,6 +155,7 @@ no_pgd: | ||||
| 		pmd = pmd_offset(pud, 0); | ||||
| 		pud_clear(pud); | ||||
| 		pmd_free(mm, pmd); | ||||
| 		mm_dec_nr_pmds(mm); | ||||
| 		pgd_clear(pgd); | ||||
| 		pud_free(mm, pud); | ||||
| 	} | ||||
|  | ||||
| @ -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: | ||||
| @ -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); | ||||
| } | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -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
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user