diff options
author | Shaohua Li <shaohua.li@intel.com> | 2011-11-14 09:34:13 +0400 |
---|---|---|
committer | Pekka Enberg <penberg@kernel.org> | 2011-11-15 22:41:00 +0400 |
commit | 9ada19342b2441f290f0043ed7c562682c8c4ede (patch) | |
tree | 702599b3b616d4bce7415012d8d4d18c7c43e5ec /mm | |
parent | f64ae042d94d376b54e7a343d93c48561e9d2e16 (diff) | |
download | linux-9ada19342b2441f290f0043ed7c562682c8c4ede.tar.xz |
slub: move discard_slab out of node lock
Lockdep reports there is potential deadlock for slub node list_lock.
discard_slab() is called with the lock hold in unfreeze_partials(),
which could trigger a slab allocation, which could hold the lock again.
discard_slab() doesn't need hold the lock actually, if the slab is
already removed from partial list.
Acked-by: Christoph Lameter <cl@linux.com>
Reported-and-tested-by: Yong Zhang <yong.zhang0@gmail.com>
Reported-and-tested-by: Julie Sullivan <kernelmail.jms@gmail.com>
Signed-off-by: Shaohua Li <shaohua.li@intel.com>
Signed-off-by: Pekka Enberg <penberg@kernel.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/slub.c | 16 |
1 files changed, 12 insertions, 4 deletions
diff --git a/mm/slub.c b/mm/slub.c index 60e16c43f88c..00efbb56a268 100644 --- a/mm/slub.c +++ b/mm/slub.c @@ -1862,7 +1862,7 @@ static void unfreeze_partials(struct kmem_cache *s) { struct kmem_cache_node *n = NULL; struct kmem_cache_cpu *c = this_cpu_ptr(s->cpu_slab); - struct page *page; + struct page *page, *discard_page = NULL; while ((page = c->partial)) { enum slab_modes { M_PARTIAL, M_FREE }; @@ -1916,14 +1916,22 @@ static void unfreeze_partials(struct kmem_cache *s) "unfreezing slab")); if (m == M_FREE) { - stat(s, DEACTIVATE_EMPTY); - discard_slab(s, page); - stat(s, FREE_SLAB); + page->next = discard_page; + discard_page = page; } } if (n) spin_unlock(&n->list_lock); + + while (discard_page) { + page = discard_page; + discard_page = discard_page->next; + + stat(s, DEACTIVATE_EMPTY); + discard_slab(s, page); + stat(s, FREE_SLAB); + } } /* |