diff options
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 45 |
1 files changed, 45 insertions, 0 deletions
@@ -272,6 +272,51 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) | |||
272 | } | 272 | } |
273 | 273 | ||
274 | /* | 274 | /* |
275 | * Some rmap walk that needs to find all ptes/hugepmds without false | ||
276 | * negatives (like migrate and split_huge_page) running concurrent | ||
277 | * with operations that copy or move pagetables (like mremap() and | ||
278 | * fork()) to be safe. They depend on the anon_vma "same_anon_vma" | ||
279 | * list to be in a certain order: the dst_vma must be placed after the | ||
280 | * src_vma in the list. This is always guaranteed by fork() but | ||
281 | * mremap() needs to call this function to enforce it in case the | ||
282 | * dst_vma isn't newly allocated and chained with the anon_vma_clone() | ||
283 | * function but just an extension of a pre-existing vma through | ||
284 | * vma_merge. | ||
285 | * | ||
286 | * NOTE: the same_anon_vma list can still be changed by other | ||
287 | * processes while mremap runs because mremap doesn't hold the | ||
288 | * anon_vma mutex to prevent modifications to the list while it | ||
289 | * runs. All we need to enforce is that the relative order of this | ||
290 | * process vmas isn't changing (we don't care about other vmas | ||
291 | * order). Each vma corresponds to an anon_vma_chain structure so | ||
292 | * there's no risk that other processes calling anon_vma_moveto_tail() | ||
293 | * and changing the same_anon_vma list under mremap() will screw with | ||
294 | * the relative order of this process vmas in the list, because we | ||
295 | * they can't alter the order of any vma that belongs to this | ||
296 | * process. And there can't be another anon_vma_moveto_tail() running | ||
297 | * concurrently with mremap() coming from this process because we hold | ||
298 | * the mmap_sem for the whole mremap(). fork() ordering dependency | ||
299 | * also shouldn't be affected because fork() only cares that the | ||
300 | * parent vmas are placed in the list before the child vmas and | ||
301 | * anon_vma_moveto_tail() won't reorder vmas from either the fork() | ||
302 | * parent or child. | ||
303 | */ | ||
304 | void anon_vma_moveto_tail(struct vm_area_struct *dst) | ||
305 | { | ||
306 | struct anon_vma_chain *pavc; | ||
307 | struct anon_vma *root = NULL; | ||
308 | |||
309 | list_for_each_entry_reverse(pavc, &dst->anon_vma_chain, same_vma) { | ||
310 | struct anon_vma *anon_vma = pavc->anon_vma; | ||
311 | VM_BUG_ON(pavc->vma != dst); | ||
312 | root = lock_anon_vma_root(root, anon_vma); | ||
313 | list_del(&pavc->same_anon_vma); | ||
314 | list_add_tail(&pavc->same_anon_vma, &anon_vma->head); | ||
315 | } | ||
316 | unlock_anon_vma_root(root); | ||
317 | } | ||
318 | |||
319 | /* | ||
275 | * Attach vma to its own anon_vma, as well as to the anon_vmas that | 320 | * Attach vma to its own anon_vma, as well as to the anon_vmas that |
276 | * the corresponding VMA in the parent process is attached to. | 321 | * the corresponding VMA in the parent process is attached to. |
277 | * Returns 0 on success, non-zero on failure. | 322 | * Returns 0 on success, non-zero on failure. |