aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorOleg Nesterov <oleg@redhat.com>2012-07-29 14:22:20 -0400
committerIngo Molnar <mingo@kernel.org>2012-07-30 05:27:20 -0400
commit9f92448ceeea5326db7d114005a7e7ac03904edf (patch)
tree42bd61d15b445d8677806adeadae99767094386c /kernel
parent089ba999dc881a7549d97c55ac9e0052d061867d (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.c27
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
244unlock_out: 247put_new:
245 unlock_page(old_page);
246 page_cache_release(new_page); 248 page_cache_release(new_page);
247 249put_old:
248put_out:
249 put_page(old_page); 250 put_page(old_page);
250 251
251 if (unlikely(ret == -EAGAIN)) 252 if (unlikely(ret == -EAGAIN))