diff options
author | Hugh Dickins <hugh@veritas.com> | 2009-01-06 17:39:32 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-06 18:59:03 -0500 |
commit | 878b63ac889df706d01048f2c110e322ad2f996d (patch) | |
tree | e0bd69b890fda939fc190675d977dd0fd75e0427 | |
parent | 2da02997e08d3efe8174c7a47696e6f7cbe69ba9 (diff) |
mm: gup persist for write permission
do_wp_page()'s VM_FAULT_WRITE return value tells __get_user_pages() that
COW has been done if necessary, though it may be leaving the pte without
write permission - for the odd case of forced writing to a readonly vma
for ptrace. At present GUP then retries the follow_page() without asking
for write permission, to escape an endless loop when forced.
But an application may be relying on GUP to guarantee a writable page
which won't be COWed again when written from userspace, whereas a race
here might leave a readonly pte in place? Change the VM_FAULT_WRITE
handling to ask follow_page() for write permission again, except in that
odd case of forced writing to a readonly vma.
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>
-rw-r--r-- | mm/memory.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/mm/memory.c b/mm/memory.c index 122d965e820f..f594bb65a9f1 100644 --- a/mm/memory.c +++ b/mm/memory.c | |||
@@ -1264,9 +1264,15 @@ int __get_user_pages(struct task_struct *tsk, struct mm_struct *mm, | |||
1264 | * do_wp_page has broken COW when necessary, | 1264 | * do_wp_page has broken COW when necessary, |
1265 | * even if maybe_mkwrite decided not to set | 1265 | * even if maybe_mkwrite decided not to set |
1266 | * pte_write. We can thus safely do subsequent | 1266 | * pte_write. We can thus safely do subsequent |
1267 | * page lookups as if they were reads. | 1267 | * page lookups as if they were reads. But only |
1268 | * do so when looping for pte_write is futile: | ||
1269 | * in some cases userspace may also be wanting | ||
1270 | * to write to the gotten user page, which a | ||
1271 | * read fault here might prevent (a readonly | ||
1272 | * page might get reCOWed by userspace write). | ||
1268 | */ | 1273 | */ |
1269 | if (ret & VM_FAULT_WRITE) | 1274 | if ((ret & VM_FAULT_WRITE) && |
1275 | !(vma->vm_flags & VM_WRITE)) | ||
1270 | foll_flags &= ~FOLL_WRITE; | 1276 | foll_flags &= ~FOLL_WRITE; |
1271 | 1277 | ||
1272 | cond_resched(); | 1278 | cond_resched(); |