Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2180

kernel-2.6.18-238.el5.src.rpm

From: Andrea Arcangeli <aarcange@redhat.com>
Date: Fri, 13 Feb 2009 16:09:48 +0100
Subject: [mm] cow vs gup race fix
Message-id: 20090213150948.GC9099@random.random
O-Subject: cow vs gup race fix
Bugzilla: 471613
RH-Acked-by: Larry Woodman <lwoodman@redhat.com>
RH-Acked-by: Rik van Riel <riel@redhat.com>

Hello,

patch to review before it goes productive, related bugs are:

https://bugzilla.redhat.com/show_bug.cgi?id=121733
https://bugzilla.redhat.com/show_bug.cgi?id=471613

This is a longstanding bug introduced when they removed my mapcount vs
count check to keep ptes pinned of pages under gup post
2.6.7. Backport from mainline.

-------
From: Hugh Dickins <hugh@veritas.com>
Date: Tue, 6 Jan 2009 22:39:33 +0000 (-0800)
Subject: mm: wp lock page before deciding cow
X-Git-Tag: v2.6.29-rc1~450
X-Git-Url: http://127.0.0.1:1234/?p=.git;a=commitdiff_plain;h=ab967d86015a19777955370deebc8262d50fed63

mm: wp lock page before deciding cow

An application may rely on get_user_pages() to give it pages writable from
userspace and shared with a driver, GUP breaking COW if necessary.  It may
mprotect() the pages' writability, off and on, from time to time.

Normally this works fine (so long as the app does not fork); but just
occasionally, under memory pressure, a readonly pte in a newly writable
area is COWed unnecessarily, breaking the link with the driver: because
do_wp_page() does trylock_page, and falls back to COW whenever that fails.

For reliable behaviour in the unshared case, when the trylock_page fails,
now unlock pagetable, lock page and relock pagetable, before deciding
whether Copy-On-Write is really necessary.

Reported-by: Zhou Yingchao
Signed-off-by: Hugh Dickins <hugh@veritas.com>
Cc: Lee Schermerhorn <lee.schermerhorn@hp.com>
Cc: Rik van Riel <riel@redhat.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
Cc: Robin Holt <holt@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

diff --git a/mm/memory.c b/mm/memory.c
index 8565f89..5233ed2 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1830,10 +1830,21 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct *vma,
 	 * not dirty accountable.
 	 */
 	if (PageAnon(old_page)) {
-		if (!TestSetPageLocked(old_page)) {
-			reuse = can_share_swap_page(old_page);
-			unlock_page(old_page);
+		if (TestSetPageLocked(old_page)) {
+			page_cache_get(old_page);
+			pte_unmap_unlock(page_table, ptl);
+			lock_page(old_page);
+			page_table = pte_offset_map_lock(mm, pmd, address,
+							 &ptl);
+			if (!pte_same(*page_table, orig_pte)) {
+				unlock_page(old_page);
+				page_cache_release(old_page);
+				goto unlock;
+			}
+			page_cache_release(old_page);
 		}
+		reuse = can_share_swap_page(old_page);
+		unlock_page(old_page);
 	} else if (unlikely((vma->vm_flags & (VM_WRITE|VM_SHARED)) ==
 					(VM_WRITE|VM_SHARED))) {
 		/*