Skip to content

Commit dd34739

Browse files
committed
mm: avoid anon_vma_chain allocation under anon_vma lock
Hugh Dickins points out that lockdep (correctly) spots a potential deadlock on the anon_vma lock, because we now do a GFP_KERNEL allocation of anon_vma_chain while doing anon_vma_clone(). The problem is that page reclaim will want to take the anon_vma lock of any anonymous pages that it will try to reclaim. So re-organize the code in anon_vma_clone() slightly: first do just a GFP_NOWAIT allocation, which will usually work fine. But if that fails, let's just drop the lock and re-do the allocation, now with GFP_KERNEL. End result: not only do we avoid the locking problem, this also ends up getting better concurrency in case the allocation does need to block. Tim Chen reports that with all these anon_vma locking tweaks, we're now almost back up to the spinlock performance. Reported-and-tested-by: Hugh Dickins <hughd@google.com> Tested-by: Tim Chen <tim.c.chen@linux.intel.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Andi Kleen <ak@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
1 parent eee2acb commit dd34739

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

mm/rmap.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ static inline void anon_vma_free(struct anon_vma *anon_vma)
112112
kmem_cache_free(anon_vma_cachep, anon_vma);
113113
}
114114

115-
static inline struct anon_vma_chain *anon_vma_chain_alloc(void)
115+
static inline struct anon_vma_chain *anon_vma_chain_alloc(gfp_t gfp)
116116
{
117-
return kmem_cache_alloc(anon_vma_chain_cachep, GFP_KERNEL);
117+
return kmem_cache_alloc(anon_vma_chain_cachep, gfp);
118118
}
119119

120120
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)
159159
struct mm_struct *mm = vma->vm_mm;
160160
struct anon_vma *allocated;
161161

162-
avc = anon_vma_chain_alloc();
162+
avc = anon_vma_chain_alloc(GFP_KERNEL);
163163
if (!avc)
164164
goto out_enomem;
165165

@@ -253,9 +253,14 @@ int anon_vma_clone(struct vm_area_struct *dst, struct vm_area_struct *src)
253253
list_for_each_entry_reverse(pavc, &src->anon_vma_chain, same_vma) {
254254
struct anon_vma *anon_vma;
255255

256-
avc = anon_vma_chain_alloc();
257-
if (!avc)
258-
goto enomem_failure;
256+
avc = anon_vma_chain_alloc(GFP_NOWAIT | __GFP_NOWARN);
257+
if (unlikely(!avc)) {
258+
unlock_anon_vma_root(root);
259+
root = NULL;
260+
avc = anon_vma_chain_alloc(GFP_KERNEL);
261+
if (!avc)
262+
goto enomem_failure;
263+
}
259264
anon_vma = pavc->anon_vma;
260265
root = lock_anon_vma_root(root, anon_vma);
261266
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)
264269
return 0;
265270

266271
enomem_failure:
267-
unlock_anon_vma_root(root);
268272
unlink_anon_vmas(dst);
269273
return -ENOMEM;
270274
}
@@ -294,7 +298,7 @@ int anon_vma_fork(struct vm_area_struct *vma, struct vm_area_struct *pvma)
294298
anon_vma = anon_vma_alloc();
295299
if (!anon_vma)
296300
goto out_error;
297-
avc = anon_vma_chain_alloc();
301+
avc = anon_vma_chain_alloc(GFP_KERNEL);
298302
if (!avc)
299303
goto out_error_free_anon_vma;
300304

0 commit comments

Comments
 (0)