diff options
author | Oleg Nesterov <oleg@redhat.com> | 2012-07-29 14:22:20 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2012-07-30 05:27:20 -0400 |
commit | 9f92448ceeea5326db7d114005a7e7ac03904edf (patch) | |
tree | 42bd61d15b445d8677806adeadae99767094386c /kernel | |
parent | 089ba999dc881a7549d97c55ac9e0052d061867d (diff) |
uprobes: Clean up and document write_opcode()->lock_page(old_page)
The comment above write_opcode()->lock_page(old_page) tells
about the race with do_wp_page(). I don't really understand
which exactly race it means, but afaics this lock_page() was not
enough to close all races with do_wp_page().
Anyway, since:
77fc4af1b59d uprobes: Change register_for_each_vma() to take mm->mmap_sem for writing
this code is always called with ->mmap_sem held for writing,
so we can forget about do_wp_page().
However, we can't simply remove this lock_page(), and the only
(afaics) reason is __replace_page()->try_to_free_swap().
Nothing in write_opcode() needs it, move it into
__replace_page() and fix the comment.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Acked-by: Srikar Dronamraju <srikar.vnet.ibm.com>
Cc: Anton Arapov <anton@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/20120729182220.GA20322@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/events/uprobes.c | 27 |
1 files changed, 14 insertions, 13 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 23c562b7fc2e..5db150b306d2 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -139,10 +139,15 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr, | |||
139 | struct mm_struct *mm = vma->vm_mm; | 139 | struct mm_struct *mm = vma->vm_mm; |
140 | spinlock_t *ptl; | 140 | spinlock_t *ptl; |
141 | pte_t *ptep; | 141 | pte_t *ptep; |
142 | int err; | ||
142 | 143 | ||
144 | /* freeze PageSwapCache() for try_to_free_swap() below */ | ||
145 | lock_page(page); | ||
146 | |||
147 | err = -EAGAIN; | ||
143 | ptep = page_check_address(page, mm, addr, &ptl, 0); | 148 | ptep = page_check_address(page, mm, addr, &ptl, 0); |
144 | if (!ptep) | 149 | if (!ptep) |
145 | return -EAGAIN; | 150 | goto unlock; |
146 | 151 | ||
147 | get_page(kpage); | 152 | get_page(kpage); |
148 | page_add_new_anon_rmap(kpage, vma, addr); | 153 | page_add_new_anon_rmap(kpage, vma, addr); |
@@ -162,7 +167,10 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr, | |||
162 | put_page(page); | 167 | put_page(page); |
163 | pte_unmap_unlock(ptep, ptl); | 168 | pte_unmap_unlock(ptep, ptl); |
164 | 169 | ||
165 | return 0; | 170 | err = 0; |
171 | unlock: | ||
172 | unlock_page(page); | ||
173 | return err; | ||
166 | } | 174 | } |
167 | 175 | ||
168 | /** | 176 | /** |
@@ -216,15 +224,10 @@ retry: | |||
216 | ret = -ENOMEM; | 224 | ret = -ENOMEM; |
217 | new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); | 225 | new_page = alloc_page_vma(GFP_HIGHUSER_MOVABLE, vma, vaddr); |
218 | if (!new_page) | 226 | if (!new_page) |
219 | goto put_out; | 227 | goto put_old; |
220 | 228 | ||
221 | __SetPageUptodate(new_page); | 229 | __SetPageUptodate(new_page); |
222 | 230 | ||
223 | /* | ||
224 | * lock page will serialize against do_wp_page()'s | ||
225 | * PageAnon() handling | ||
226 | */ | ||
227 | lock_page(old_page); | ||
228 | /* copy the page now that we've got it stable */ | 231 | /* copy the page now that we've got it stable */ |
229 | vaddr_old = kmap_atomic(old_page); | 232 | vaddr_old = kmap_atomic(old_page); |
230 | vaddr_new = kmap_atomic(new_page); | 233 | vaddr_new = kmap_atomic(new_page); |
@@ -237,15 +240,13 @@ retry: | |||
237 | 240 | ||
238 | ret = anon_vma_prepare(vma); | 241 | ret = anon_vma_prepare(vma); |
239 | if (ret) | 242 | if (ret) |
240 | goto unlock_out; | 243 | goto put_new; |
241 | 244 | ||
242 | ret = __replace_page(vma, vaddr, old_page, new_page); | 245 | ret = __replace_page(vma, vaddr, old_page, new_page); |
243 | 246 | ||
244 | unlock_out: | 247 | put_new: |
245 | unlock_page(old_page); | ||
246 | page_cache_release(new_page); | 248 | page_cache_release(new_page); |
247 | 249 | put_old: | |
248 | put_out: | ||
249 | put_page(old_page); | 250 | put_page(old_page); |
250 | 251 | ||
251 | if (unlikely(ret == -EAGAIN)) | 252 | if (unlikely(ret == -EAGAIN)) |