[patch] fix cpucontrol <-> cache_chain_mutex lock inversion bug

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



fix cpucontrol/cache_chain_mutex lock ordering in the SLAB code.

kmem_cache_create() was doing lock_cpu_hotplug() after taking 
cache_chain_mutex. This can lead to deadlocks if a hotplug CPU is being 
brought up or down via cpuup_callback(), which takes cache_chain_mutex 
after lock_cpu_hotplug() is done.

Since the SLAB code has no choice about the cpucontrol already being 
taken at cpuup_callback(), the cache_chain_mutex has to nest inside 
lock_cpu_hotplug() - not the other way around. So the fix is to change 
kmem_cache_create() to take the cpu hotplug lock first.

the interesting thing about this bug is that i found it via a new 
CONFIG_DEBUG_MUTEXES feature i'm working on, which validates locking 
rules by mapping lock dependencies runtime, and "auto-learns" the 
locking rules - and thus detects any later violations of the locking 
rules. This code is able to detect complex lock inversion bugs (such as 
this one) even when they do not cause an actual deadlock yet. The system 
where i ran the debugger is not hotplug-cpu capable, it purely ran the 
two codepaths, at which point the detector warned about the lockup 
potential.

to reproduce the real lockup i'd need to simulate a hotplug CPU setup, 
and i'd also need to run kmem_cache_create() in parallel [which is a 
rarely called function], while also running the CPU hotplug add/remove 
code. Even knowing the precise bug it would be quite complex to set up 
the proper circumstances and reproduce the lockup.

the debug output was:

 =====================================
 [ BUG: lock inversion bug detected! ]
 -------------------------------------
 swapper/1 is trying to acquire lock {cache_chain_mutex} at:
 - cpuup_callback+0x42/0x2de
 and task is already holding lock {cpucontrol},
 which would create the following lock dependency:
  {cpucontrol} -> {cache_chain_mutex}
 but we recorded an inverse lock dependency between them in the past:
  {cache_chain_mutex} -> {cpucontrol}
 at:
 - __lock_cpu_hotplug+0x38/0x52
 which could lead to deadlocks!
 [...]

Signed-off-by: Ingo Molnar <[email protected]>

----

 mm/slab.c |   17 ++++++++++++-----
 1 files changed, 12 insertions(+), 5 deletions(-)

Index: linux/mm/slab.c
===================================================================
--- linux.orig/mm/slab.c
+++ linux/mm/slab.c
@@ -635,7 +635,12 @@ static kmem_cache_t cache_cache = {
 #endif
 };
 
-/* Guard access to the cache-chain. */
+/*
+ * Guard access to the cache-chain.
+ *
+ * Lock ordering: if lock_cpu_hotplug() is done, it must be
+ * called before cache_chain_mutex is acquired.
+ */
 static DEFINE_MUTEX(cache_chain_mutex);
 static struct list_head cache_chain;
 
@@ -1596,6 +1601,10 @@ kmem_cache_create (const char *name, siz
 		BUG();
 	}
 
+	/*
+	 * Don't let CPUs to come and go.
+	 */
+	lock_cpu_hotplug();
 	mutex_lock(&cache_chain_mutex);
 
 	list_for_each(p, &cache_chain) {
@@ -1797,9 +1806,6 @@ kmem_cache_create (const char *name, siz
 	cachep->dtor = dtor;
 	cachep->name = name;
 
-	/* Don't let CPUs to come and go */
-	lock_cpu_hotplug();
-
 	if (g_cpucache_up == FULL) {
 		enable_cpucache(cachep);
 	} else {
@@ -1857,12 +1863,13 @@ kmem_cache_create (const char *name, siz
 
 	/* cache setup completed, link it into the list */
 	list_add(&cachep->next, &cache_chain);
-	unlock_cpu_hotplug();
       oops:
 	if (!cachep && (flags & SLAB_PANIC))
 		panic("kmem_cache_create(): failed to create slab `%s'\n",
 		      name);
 	mutex_unlock(&cache_chain_mutex);
+	unlock_cpu_hotplug();
+
 	return cachep;
 }
 EXPORT_SYMBOL(kmem_cache_create);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux