On Thu, 2011-06-16 at 20:58 -0700, Linus Torvalds wrote: > Ok, I'm still thinking. I have an approach that I think will handle it > fairly cleanly, but that involves walking the same_vma list twice: > once to actually unlink the anon_vma's under the lock, and then a > second pass that does the rest. It should work. Something like so? Compiles and runs the benchmark in question. --- Index: linux-2.6/mm/rmap.c =================================================================== --- linux-2.6.orig/mm/rmap.c +++ linux-2.6/mm/rmap.c @@ -324,36 +324,52 @@ int anon_vma_fork(struct vm_area_struct return -ENOMEM; } -static void anon_vma_unlink(struct anon_vma_chain *anon_vma_chain) +static int anon_vma_unlink(struct anon_vma_chain *anon_vma_chain, struct anon_vma *anon_vma) { - struct anon_vma *anon_vma = anon_vma_chain->anon_vma; - int empty; - - /* If anon_vma_fork fails, we can get an empty anon_vma_chain. */ - if (!anon_vma) - return; - - anon_vma_lock(anon_vma); list_del(&anon_vma_chain->same_anon_vma); /* We must garbage collect the anon_vma if it's empty */ - empty = list_empty(&anon_vma->head); - anon_vma_unlock(anon_vma); + if (list_empty(&anon_vma->head)) + return 1; - if (empty) - put_anon_vma(anon_vma); + return 0; } void unlink_anon_vmas(struct vm_area_struct *vma) { struct anon_vma_chain *avc, *next; + struct anon_vma *root = NULL; /* * Unlink each anon_vma chained to the VMA. This list is ordered * from newest to oldest, ensuring the root anon_vma gets freed last. */ list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { - anon_vma_unlink(avc); + struct anon_vma *anon_vma = avc->anon_vma; + + /* If anon_vma_fork fails, we can get an empty anon_vma_chain. */ + if (anon_vma) { + root = lock_anon_vma_root(root, anon_vma); + /* Leave empty anon_vmas on the list. */ + if (anon_vma_unlink(avc, anon_vma)) + continue; + } + list_del(&avc->same_vma); + anon_vma_chain_free(avc); + } + unlock_anon_vma_root(root); + + /* + * Iterate the list once more, it now only contains empty and unlinked + * anon_vmas, destroy them. Could not do before due to anon_vma_free() + * needing to acquire the anon_vma->root->mutex. + */ + list_for_each_entry_safe(avc, next, &vma->anon_vma_chain, same_vma) { + struct anon_vma *anon_vma = avc->anon_vma; + + if (anon_vma) + put_anon_vma(anon_vma); + list_del(&avc->same_vma); anon_vma_chain_free(avc); } -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href