On Fri, Jun 17, 2011 at 11:32 AM, Peter Zijlstra <peterz@xxxxxxxxxxxxx> wrote: > > something like so I guess, completely untested etc.. Having gone over it a bit more, I actually think I prefer to just special-case the allocation instead. We already have to drop the anon_vma lock for the "out of memory" case, and a slight re-organization of clone_anon_vma() makes it easy to just first try a NOIO allocation with the lock still held, and then if that fails do the "drop lock, retry, and hard-fail" case. IOW, something like the attached (on top of the patches already posted except for your memory reclaim thing) Hugh, does this fix the lockdep issue? Linus
mm/rmap.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-) diff --git a/mm/rmap.c b/mm/rmap.c index 68756a77ef87..27dfd3b82b0f 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -112,9 +112,9 @@ static inline void anon_vma_free(struct anon_vma *anon_vma) kmem_cache_free(anon_vma_cachep, anon_vma); } -static inline struct anon_vma_chain *anon_vma_chain_alloc(void) +static inline struct anon_vma_chain *anon_vma_chain_alloc(gfp_t gfp) { - return kmem_cache_alloc(anon_vma_chain_cachep, GFP_KERNEL); + return kmem_cache_alloc(anon_vma_chain_cachep, gfp); } static void anon_vma_chain_free(struct anon_vma_chain *anon_vma_chain) @@ -159,7 +159,7 @@ int anon_vma_prepare(struct vm_area_struct *vma) struct mm_struct *mm = vma->vm_mm; struct anon_vma *allocated; - avc = anon_vma_chain_alloc(); + avc = anon_vma_chain_alloc(GFP_KERNEL); if (!avc) goto out_enomem; @@ -253,9 +253,14 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) { struct anon_vma *anon_vma; - avc = anon_vma_chain_alloc(); - if (!avc) - goto enomem_failure; + avc = anon_vma_chain_alloc(GFP_NOWAIT | __GFP_NOWARN); + if (unlikely(!avc)) { + unlock_anon_vma_root(root); + root = NULL; + avc = anon_vma_chain_alloc(GFP_KERNEL); + if (!avc) + goto enomem_failure; + } anon_vma = pavc->anon_vma; root = lock_anon_vma_root(root, anon_vma); anon_vma_chain_link(dst, avc, anon_vma); @@ -264,7 +269,6 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src) return 0; enomem_failure: - unlock_anon_vma_root(root); unlink_anon_vmas(dst); return -ENOMEM; } @@ -294,7 +298,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma) anon_vma = anon_vma_alloc(); if (!anon_vma) goto out_error; - avc = anon_vma_chain_alloc(); + avc = anon_vma_chain_alloc(GFP_KERNEL); if (!avc) goto out_error_free_anon_vma;