diff options
Diffstat (limited to 'mm/memory.c')
-rw-r--r-- | mm/memory.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/mm/memory.c b/mm/memory.c index 347e5fad1cfa..e01abb908b6b 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1247,16 +1247,24 @@ static inline unsigned long zap_pmd_range(struct mmu_gather *tlb, | |||
1247 | do { | 1247 | do { |
1248 | next = pmd_addr_end(addr, end); | 1248 | next = pmd_addr_end(addr, end); |
1249 | if (pmd_trans_huge(*pmd)) { | 1249 | if (pmd_trans_huge(*pmd)) { |
1250 | if (next-addr != HPAGE_PMD_SIZE) { | 1250 | if (next - addr != HPAGE_PMD_SIZE) { |
1251 | VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); | 1251 | VM_BUG_ON(!rwsem_is_locked(&tlb->mm->mmap_sem)); |
1252 | split_huge_page_pmd(vma->vm_mm, pmd); | 1252 | split_huge_page_pmd(vma->vm_mm, pmd); |
1253 | } else if (zap_huge_pmd(tlb, vma, pmd, addr)) | 1253 | } else if (zap_huge_pmd(tlb, vma, pmd, addr)) |
1254 | continue; | 1254 | goto next; |
1255 | /* fall through */ | 1255 | /* fall through */ |
1256 | } | 1256 | } |
1257 | if (pmd_none_or_clear_bad(pmd)) | 1257 | /* |
1258 | continue; | 1258 | * Here there can be other concurrent MADV_DONTNEED or |
1259 | * trans huge page faults running, and if the pmd is | ||
1260 | * none or trans huge it can change under us. This is | ||
1261 | * because MADV_DONTNEED holds the mmap_sem in read | ||
1262 | * mode. | ||
1263 | */ | ||
1264 | if (pmd_none_or_trans_huge_or_clear_bad(pmd)) | ||
1265 | goto next; | ||
1259 | next = zap_pte_range(tlb, vma, pmd, addr, next, details); | 1266 | next = zap_pte_range(tlb, vma, pmd, addr, next, details); |
1267 | next: | ||
1260 | cond_resched(); | 1268 | cond_resched(); |
1261 | } while (pmd++, addr = next, addr != end); | 1269 | } while (pmd++, addr = next, addr != end); |
1262 | 1270 | ||