aboutsummaryrefslogtreecommitdiffstats
path: root/mm/hugetlb.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r--mm/hugetlb.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 450493d25572..2ef66a2a148d 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2293,6 +2293,9 @@ retry_avoidcopy:
2293 outside_reserve = 1; 2293 outside_reserve = 1;
2294 2294
2295 page_cache_get(old_page); 2295 page_cache_get(old_page);
2296
2297 /* Drop page_table_lock as buddy allocator may be called */
2298 spin_unlock(&mm->page_table_lock);
2296 new_page = alloc_huge_page(vma, address, outside_reserve); 2299 new_page = alloc_huge_page(vma, address, outside_reserve);
2297 2300
2298 if (IS_ERR(new_page)) { 2301 if (IS_ERR(new_page)) {
@@ -2310,19 +2313,25 @@ retry_avoidcopy:
2310 if (unmap_ref_private(mm, vma, old_page, address)) { 2313 if (unmap_ref_private(mm, vma, old_page, address)) {
2311 BUG_ON(page_count(old_page) != 1); 2314 BUG_ON(page_count(old_page) != 1);
2312 BUG_ON(huge_pte_none(pte)); 2315 BUG_ON(huge_pte_none(pte));
2316 spin_lock(&mm->page_table_lock);
2313 goto retry_avoidcopy; 2317 goto retry_avoidcopy;
2314 } 2318 }
2315 WARN_ON_ONCE(1); 2319 WARN_ON_ONCE(1);
2316 } 2320 }
2317 2321
2322 /* Caller expects lock to be held */
2323 spin_lock(&mm->page_table_lock);
2318 return -PTR_ERR(new_page); 2324 return -PTR_ERR(new_page);
2319 } 2325 }
2320 2326
2321 spin_unlock(&mm->page_table_lock);
2322 copy_huge_page(new_page, old_page, address, vma); 2327 copy_huge_page(new_page, old_page, address, vma);
2323 __SetPageUptodate(new_page); 2328 __SetPageUptodate(new_page);
2324 spin_lock(&mm->page_table_lock);
2325 2329
2330 /*
2331 * Retake the page_table_lock to check for racing updates
2332 * before the page tables are altered
2333 */
2334 spin_lock(&mm->page_table_lock);
2326 ptep = huge_pte_offset(mm, address & huge_page_mask(h)); 2335 ptep = huge_pte_offset(mm, address & huge_page_mask(h));
2327 if (likely(pte_same(huge_ptep_get(ptep), pte))) { 2336 if (likely(pte_same(huge_ptep_get(ptep), pte))) {
2328 /* Break COW */ 2337 /* Break COW */