Commit 56c9cfb1 authored by Naoya Horiguchi's avatar Naoya Horiguchi Committed by Linus Torvalds

hugetlb, rmap: fix confusing page locking in hugetlb_cow()

The "if (!trylock_page)" block in the avoidcopy path of hugetlb_cow()
looks confusing and is buggy.  Originally this trylock_page() was
intended to make sure that old_page is locked even when old_page !=
pagecache_page, because then only pagecache_page is locked.

This patch fixes it by moving page locking into hugetlb_fault().
Signed-off-by: default avatarNaoya Horiguchi <n-horiguchi@ah.jp.nec.com>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent cd67f0d2
...@@ -2324,11 +2324,8 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2324,11 +2324,8 @@ static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma,
* and just make the page writable */ * and just make the page writable */
avoidcopy = (page_mapcount(old_page) == 1); avoidcopy = (page_mapcount(old_page) == 1);
if (avoidcopy) { if (avoidcopy) {
if (!trylock_page(old_page)) {
if (PageAnon(old_page)) if (PageAnon(old_page))
page_move_anon_rmap(old_page, vma, address); page_move_anon_rmap(old_page, vma, address);
} else
unlock_page(old_page);
set_huge_ptep_writable(vma, address, ptep); set_huge_ptep_writable(vma, address, ptep);
return 0; return 0;
} }
...@@ -2631,10 +2628,16 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2631,10 +2628,16 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
vma, address); vma, address);
} }
if (!pagecache_page) { /*
* hugetlb_cow() requires page locks of pte_page(entry) and
* pagecache_page, so here we need take the former one
* when page != pagecache_page or !pagecache_page.
* Note that locking order is always pagecache_page -> page,
* so no worry about deadlock.
*/
page = pte_page(entry); page = pte_page(entry);
if (page != pagecache_page)
lock_page(page); lock_page(page);
}
spin_lock(&mm->page_table_lock); spin_lock(&mm->page_table_lock);
/* Check for a racing update before calling hugetlb_cow */ /* Check for a racing update before calling hugetlb_cow */
...@@ -2661,9 +2664,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, ...@@ -2661,9 +2664,8 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
if (pagecache_page) { if (pagecache_page) {
unlock_page(pagecache_page); unlock_page(pagecache_page);
put_page(pagecache_page); put_page(pagecache_page);
} else {
unlock_page(page);
} }
unlock_page(page);
out_mutex: out_mutex:
mutex_unlock(&hugetlb_instantiation_mutex); mutex_unlock(&hugetlb_instantiation_mutex);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment