Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+12 −10
Original line number Original line Diff line number Diff line
@@ -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,
								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,
	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);