Skip to contentSkip to conversation

slub: Fix sysfs circular locking dependency

PATCH In review Pekka Enberg 5 participants 27 messages Jan 4, 2011 – Jan 11, 2011

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 slub: Fix sysfs circular locking dependency

[ Bart, does this patch fix the problem for you? ]

This patch fixes the following potential deadlock reported by Bart Van Assche:

=======================================================
[ INFO: possible circular locking dependency detected ] 2.6.37-rc6+ #12
-------------------------------------------------------
grep/10562 is trying to acquire lock:
(slub_lock){+++++.}, at: [<ffffffff8114baec>] show_slab_objects+0xfc/0x390

but task is already holding lock:
(s_active#182){++++.+}, at: [<ffffffff811c4b16>] sysfs_read_file+0x96/0x1c0

which lock already depends on the new lock.

the existing dependency chain (in reverse order) is:

-> #1 (s_active#182){++++.+}:

         [<ffffffff81096b00>] lock_acquire+0xa0/0x150
         [<ffffffff811c5b77>] sysfs_deactivate+0x157/0x1c0
         [<ffffffff811c6273>] sysfs_addrm_finish+0x43/0x70
         [<ffffffff811c637e>] sysfs_remove_dir+0x7e/0xa0
         [<ffffffff812c3616>] kobject_del+0x16/0x40
         [<ffffffff8114c132>] kmem_cache_destroy+0x2f2/0x380
         [<ffffffffa01b4bd1>] 0xffffffffa01b4bd1
         [<ffffffff810a1682>] sys_delete_module+0x1a2/0x280
         [<ffffffff81003042>] system_call_fastpath+0x16/0x1b

-> #0 (slub_lock){+++++.}:

         [<ffffffff810968c0>] __lock_acquire+0x1370/0x1510
         [<ffffffff81096b00>] lock_acquire+0xa0/0x150
         [<ffffffff81548f41>] down_read+0x51/0xa0
         [<ffffffff8114baec>] show_slab_objects+0xfc/0x390
         [<ffffffff8114be33>] objects_show+0x13/0x20
         [<ffffffff81145e92>] slab_attr_show+0x22/0x30
         [<ffffffff811c4b59>] sysfs_read_file+0xd9/0x1c0
         [<ffffffff81158f8d>] vfs_read+0xcd/0x1a0
         [<ffffffff81159854>] sys_read+0x54/0x90
         [<ffffffff81003042>] system_call_fastpath+0x16/0x1b

other info that might help us debug this:

2 locks held by grep/10562:
#0: (&buffer->mutex){+.+.+.}, at: [<ffffffff811c4ac6>] sysfs_read_file+0x46/0x1c0 #1: (s_active#182){++++.+}, at: [<ffffffff811c4b16>] sysfs_read_file+0x96/0x1c0

  stack backtrace:
  Pid: 10562, comm: grep Tainted: G        W   2.6.37-rc6+ #12
  Call Trace:
   [<ffffffff81094379>] print_circular_bug+0xf9/0x100
   [<ffffffff810968c0>] __lock_acquire+0x1370/0x1510
   [<ffffffff8100a3d9>] ? sched_clock+0x9/0x10
   [<ffffffff81148a5c>] ? check_object+0xac/0x250
   [<ffffffff81096b00>] lock_acquire+0xa0/0x150
   [<ffffffff8114baec>] ? show_slab_objects+0xfc/0x390
   [<ffffffff8109522d>] ? trace_hardirqs_on_caller+0x14d/0x190
   [<ffffffff81548f41>] down_read+0x51/0xa0
   [<ffffffff8114baec>] ? show_slab_objects+0xfc/0x390
   [<ffffffff8114baec>] show_slab_objects+0xfc/0x390
   [<ffffffff8114be33>] objects_show+0x13/0x20
   [<ffffffff81145e92>] slab_attr_show+0x22/0x30
   [<ffffffff811c4b59>] sysfs_read_file+0xd9/0x1c0
   [<ffffffff81158f8d>] vfs_read+0xcd/0x1a0
   [<ffffffff81159854>] sys_read+0x54/0x90
   [<ffffffff81003042>] system_call_fastpath+0x16/0x1b

The problem here is that locking order is implicitly (1) sysfs internals and
(2) slub_lock but we violate that in kmem_cache_destroy().

Reference: https://bugzilla.kernel.org/show_bug.cgi?id=25622

Cc Bart Van Assche <[email protected]>
Cc Andrew Morton <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc David Rientjes <[email protected]>
---
 mm/slub.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)
mm/slub.c +6 -0
index bec0e35..9831004 100644
@@ -2516,7 +2516,13 @@ void kmem_cache_destroy(struct kmem_cache *s)
 		}
 		if (s->flags & SLAB_DESTROY_BY_RCU)
 			rcu_barrier();
+		/*
+		 * The locking order is (1) sysfs internal locks and (2)
+		 * slub_lock so drop the latter to avoid a deadlock.
+		 */
+		up_write(&slub_lock);
 		sysfs_slab_remove(s);
+		return;
 	}
 	up_write(&slub_lock);
 }
Signature · 1 line
1.7.0.4
#1 lore raw
Quoted 8 lines · Pekka Enberg
mm/slub.c +0 -0
index bec0e35..9831004 100644
@@ -2516,7 +2516,13 @@ void kmem_cache_destroy(struct kmem_cache *s)
 		}
 		if (s->flags & SLAB_DESTROY_BY_RCU)
 			rcu_barrier();

mm/slub.c void kmem_cache_destroy(struct kmem_cache *s) · line 2528

Quoted 10 lines
mm/slub.c +6 -0
+		/*
+		 * The locking order is (1) sysfs internal locks and (2)
+		 * slub_lock so drop the latter to avoid a deadlock.
+		 */
+		up_write(&slub_lock);
 		sysfs_slab_remove(s);
+		return;
 	}
 	up_write(&slub_lock);
 }

slub_lock protects slab_state following kmem_cache_init() if caches are created/destroyed prior to the sysfs slab initcall setting the global variable, so couldn't this leak the kobject if its initialization and add was deferred on kmem_cache_create() and added by slab_sysfs_init()?

#2 lore raw
Quoted 4 lines · David Rientjes

slub_lock protects slab_state following kmem_cache_init() if caches are created/destroyed prior to the sysfs slab initcall setting the global variable, so couldn't this leak the kobject if its initialization and add was deferred on kmem_cache_create() and added by slab_sysfs_init()?

Potentially.

Also note that the same lock inversion occurs in kmem_cache_create(). slub lock is taken and then sysfs operations are performed.

The problem is that slub_lock has multiple roles:

1. Protect the list of slab caches and the slab_state (thats why its mainly used in kmem_cache_destroy and kmem_cache_create)

2. Protect against removal and adding of new cpus and nodes (show_slab_objects)

If we could create another lock that protects against new cpus / nodes being added and removed then we could take that lock in show_slab_objects() instead.

IMHO the lock order must have the slub_lock at the top.

The other lock that would prevent adding/removal of nodes / cpu can be taken in show_slab_objects and in the corresponding hotplug functions. We do not need to take the lock at all in show_slab_objects cpu and memory hotplug are not enabled. Maybe there is a hotplug specific lock that can be used instead?

#3 lore raw

How about this solution? In the common case of kernels without hotplug support there will be no locking at all.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

---
 mm/slub.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
mm/slub.c +2 -2
Index: linux-2.6/mm/slub.c
===================================================================
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
 		}
 	}
 
-	down_read(&slub_lock);
+	lock_memory_hotplug();
 #ifdef CONFIG_SLUB_DEBUG
 	if (flags & SO_ALL) {
 		for_each_node_state(node, N_NORMAL_MEMORY) {
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
 			x += sprintf(buf + x, " N%d=%lu",
 					node, nodes[node]);
 #endif
-	up_read(&slub_lock);
+	unlock_memory_hotplug();
 	kfree(nodes);
 	return x + sprintf(buf + x, "\n");
 }
#4 lore raw
Quoted 34 lines · Christoph Lameter

How about this solution? In the common case of kernels without hotplug support there will be no locking at all.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

---
 mm/slub.c |    4 ++--

 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6/mm/slub.c
===================================================================

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
                }
        }
 
-       down_read(&slub_lock);
+       lock_memory_hotplug();
  #ifdef CONFIG_SLUB_DEBUG
        if (flags & SO_ALL) {
                for_each_node_state(node, N_NORMAL_MEMORY) {

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 static ssize_t show_slab_objects(struct · line 3868

Quoted 8 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
  #endif
-       up_read(&slub_lock);
+       unlock_memory_hotplug();
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
  }

Makes sense. Bart, does this fix the problem for you?

#5 lore raw
Quoted 30 lines · Pekka Enberg
Quoted 28 lines · Christoph Lameter

How about this solution? In the common case of kernels without hotplug support there will be no locking at all.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

---
 mm/slub.c |    4 ++--

 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6/mm/slub.c
===================================================================

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +0 -0
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
                }
        }
 
Quoted 16 lines
Quoted 6 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
-       down_read(&slub_lock);
+       lock_memory_hotplug();
  #ifdef CONFIG_SLUB_DEBUG
        if (flags & SO_ALL) {
                for_each_node_state(node, N_NORMAL_MEMORY) {

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 static ssize_t show_slab_objects(struct · line 3868

Quoted 8 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
  #endif
-       up_read(&slub_lock);
+       unlock_memory_hotplug();
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
  }

Makes sense. Bart, does this fix the problem for you?

The action sequence that had triggered this sequence (invoke kmem_cache_create(); read all files in /sys/kernel/slab; invoke kmem_cache_destroy()) does now pass without triggering lock inversion complaints.

Bart.

#6 lore raw
Quoted 48 lines · Bart Van Assche
Quoted 30 lines · Pekka Enberg
Quoted 28 lines · Christoph Lameter

How about this solution? In the common case of kernels without hotplug support there will be no locking at all.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

---
 mm/slub.c |    4 ++--

 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6/mm/slub.c
===================================================================

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +0 -0
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
                }
        }
 
Quoted 16 lines
Quoted 6 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
-       down_read(&slub_lock);
+       lock_memory_hotplug();
  #ifdef CONFIG_SLUB_DEBUG
        if (flags & SO_ALL) {
                for_each_node_state(node, N_NORMAL_MEMORY) {

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 static ssize_t show_slab_objects(struct · line 3868

Quoted 8 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
  #endif
-       up_read(&slub_lock);
+       unlock_memory_hotplug();
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
  }

Makes sense. Bart, does this fix the problem for you?

Quoted 4 lines

The action sequence that had triggered this sequence (invoke kmem_cache_create(); read all files in /sys/kernel/slab; invoke kmem_cache_destroy()) does now pass without triggering lock inversion complaints.

Thanks for testing. David, does Christoph's patch look OK to you?

#7 lore raw
Quoted 41 lines · Pekka Enberg
Quoted 41 lines
Quoted 40 lines
Quoted 30 lines

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

---
 mm/slub.c |    4 ++--

 1 file changed, 2 insertions(+), 2 deletions(-)

Index: linux-2.6/mm/slub.c
===================================================================

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
                }
        }
 
-       down_read(&slub_lock);
+       lock_memory_hotplug();
  #ifdef CONFIG_SLUB_DEBUG
        if (flags & SO_ALL) {
                for_each_node_state(node, N_NORMAL_MEMORY) {

mm/slub.c 2011-01-05 09:56:27.000000000 -0600 static ssize_t show_slab_objects(struct · line 3868

Quoted 8 lines
mm/slub.c 2011-01-05 09:56:27.000000000 -0600 renamed from mm/slub.c    2011-01-05 09:55:34.000000000 -0600 +1 -1
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
                        x += sprintf(buf + x, " N%d=%lu",
                                        node, nodes[node]);
  #endif
-       up_read(&slub_lock);
+       unlock_memory_hotplug();
        kfree(nodes);
        return x + sprintf(buf + x, "\n");
  }

Makes sense. Bart, does this fix the problem for you?

Quoted 7 lines
Quoted 4 lines

The action sequence that had triggered this sequence (invoke kmem_cache_create(); read all files in /sys/kernel/slab; invoke kmem_cache_destroy()) does now pass without triggering lock inversion complaints.

Thanks for testing. David, does Christoph's patch look OK to you?

I think it certainly fixes the problem at hand, but I think we also need to do lock_memory_hotplug() for memory hotplug in slab_mem_going_online_callback() to make show_slab_objects() consistent when being printed during concurrent node hot-add since it sets bits in N_NORMAL_MEMORY. The MEM_OFFLINE callback is already handled at a higher level by taking the lock in the hotplug layer, but we need to protect the MEM_GOING_ONLINE and MEM_CANCEL_ONLINE callbacks if slub_lock is no longer used to protect node arrays (which was admittedly always convenient since it's typically associated with an iteration through slab_caches).

#8 lore raw
Quoted 12 lines · David Rientjes
Quoted 2 lines

Thanks for testing. David, does Christoph's patch look OK to you?

I think it certainly fixes the problem at hand, but I think we also need to do lock_memory_hotplug() for memory hotplug in slab_mem_going_online_callback() to make show_slab_objects() consistent when being printed during concurrent node hot-add since it sets bits in N_NORMAL_MEMORY. The MEM_OFFLINE callback is already handled at a higher level by taking the lock in the hotplug layer, but we need to protect the MEM_GOING_ONLINE and MEM_CANCEL_ONLINE callbacks if slub_lock is no longer used to protect node arrays (which was admittedly always convenient since it's typically associated with an iteration through slab_caches).

Hmm, I would have expected the callbacks all to be done under hotplug locking.

The MEM_GOING_ONLINE callback is not that critical since a node that is coming online presumably has only a minimal set of objects necessary for potential future allocations.

slab_mem_going_online_callback() etc already take the slub_lock since they have to iterate over the list of slab caches in existence. We could take the hotplug lock there as well.

Kame-san: Can you enlighten us on hotplug locking? And also check this patch?

#9 lore raw
Quoted 7 lines · Christoph Lameter

slab_mem_going_online_callback() etc already take the slub_lock since they have to iterate over the list of slab caches in existence. We could take the hotplug lock there as well.

Kame-san: Can you enlighten us on hotplug locking? And also check this patch?

Yeah, I was going to suggest doing the lock_memory_hotplug() before taking slub_lock in the callback, but I really think it should be done in online_pages(). Since the offline case is already handled, this would expand the semantics of lock_memory_hotplug() to serialize the access of data structures that can change in a memory hotplug notifier callback without locking at the lower level.

#10 lore raw
In reply to Christoph Lameter
Quoted 22 lines · On Thu, 6 Jan 2011 12:10:59 -0600 (CST) Christoph Lameter <[email protected]> wrote:
Quoted 12 lines · David Rientjes
Quoted 2 lines

Thanks for testing. David, does Christoph's patch look OK to you?

I think it certainly fixes the problem at hand, but I think we also need to do lock_memory_hotplug() for memory hotplug in slab_mem_going_online_callback() to make show_slab_objects() consistent when being printed during concurrent node hot-add since it sets bits in N_NORMAL_MEMORY. The MEM_OFFLINE callback is already handled at a higher level by taking the lock in the hotplug layer, but we need to protect the MEM_GOING_ONLINE and MEM_CANCEL_ONLINE callbacks if slub_lock is no longer used to protect node arrays (which was admittedly always convenient since it's typically associated with an iteration through slab_caches).

Hmm, I would have expected the callbacks all to be done under hotplug locking.

The MEM_GOING_ONLINE callback is not that critical since a node that is coming online presumably has only a minimal set of objects necessary for potential future allocations.

Quoted 7 lines

slab_mem_going_online_callback() etc already take the slub_lock since they have to iterate over the list of slab caches in existence. We could take the hotplug lock there as well.

Kame-san: Can you enlighten us on hotplug locking? And also check this patch?

IIRC, lock_memory_hotplug() is a new lock in 2.6.37 added by Kosaki

http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=20d6c96b5f1cad5c5da4641945ec17a1d9a1afc8

as bugfix.

This lock is for avoiding race with hwpoison and memory hotplug and original lock (before replacement) was for avoiding race with hibernation. online_pages() was out of lock because it just makes PG_reserved page to be free page, not racy with hibernation.

But, nice catch. I think MEM_GOING_ONLINE, MEM_ONLINE should be done under lock_memory_hotplug. So, could you update your patch and modify online_pages() ?

IIUC, online_pages() is an user interface function and there will be no downside to insert lock there. online_pages() should be serialized.

Thanks,
-Kame

#11 lore raw
Quoted 5 lines · KAMEZAWA Hiroyuki

But, nice catch. I think MEM_GOING_ONLINE, MEM_ONLINE should be done under lock_memory_hotplug. So, could you update your patch and modify online_pages() ?

IIUC, online_pages() is an user interface function and there will be no downside to insert lock there. online_pages() should be serialized.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

online_pages() does not acquire the memory_hotplug lock. So add the missing locking there.

---
 mm/memory_hotplug.c |   17 +++++++++++------
 mm/slub.c           |    4 ++--
 2 files changed, 13 insertions(+), 8 deletions(-)
mm/slub.c +2 -2
Index: linux-2.6/mm/slub.c
===================================================================
@@ -3821,7 +3821,7 @@ static ssize_t show_slab_objects(struct
 		}
 	}
 
-	down_read(&slub_lock);
+	lock_memory_hotplug();
 #ifdef CONFIG_SLUB_DEBUG
 	if (flags & SO_ALL) {
 		for_each_node_state(node, N_NORMAL_MEMORY) {
@@ -3862,7 +3862,7 @@ static ssize_t show_slab_objects(struct
 			x += sprintf(buf + x, " N%d=%lu",
 					node, nodes[node]);
 #endif
-	up_read(&slub_lock);
+	unlock_memory_hotplug();
 	kfree(nodes);
 	return x + sprintf(buf + x, "\n");
 }
mm/memory_hotplug.c +11 -6
Index: linux-2.6/mm/memory_hotplug.c
===================================================================
@@ -415,12 +415,12 @@ int online_pages(unsigned long pfn, unsi
 	if (node_present_pages(nid) == 0)
 		arg.status_change_nid = nid;
 
+	lock_memory_hotplug();
 	ret = memory_notify(MEM_GOING_ONLINE, &arg);
 	ret = notifier_to_errno(ret);
-	if (ret) {
-		memory_notify(MEM_CANCEL_ONLINE, &arg);
-		return ret;
-	}
+	if (ret)
+		goto cancel;
+
 	/*
 	 * This doesn't need a lock to do pfn_to_page().
 	 * The section can't be removed here because of the
@@ -442,8 +442,7 @@ int online_pages(unsigned long pfn, unsi
 		mutex_unlock(&zonelists_mutex);
 		printk(KERN_DEBUG "online_pages %lx at %lx failed\n",
 			nr_pages, pfn);
-		memory_notify(MEM_CANCEL_ONLINE, &arg);
-		return ret;
+		goto cancel;
 	}
 
 	zone->present_pages += onlined_pages;
@@ -468,7 +467,13 @@ int online_pages(unsigned long pfn, unsi
 	if (onlined_pages)
 		memory_notify(MEM_ONLINE, &arg);
 
+	unlock_memory_hotplug();
 	return 0;
+
+cancel:
+	memory_notify(MEM_CANCEL_ONLINE, &arg);
+	unlock_memory_hotplug();
+	return ret;
 }
 #endif /* CONFIG_MEMORY_HOTPLUG_SPARSE */
 
reviewer Acked-by
#12 lore raw
Quoted 9 lines · Christoph Lameter

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

Because memory hotplug is the only time s->node[] is modified after the sysfs files are created, which is the only time show_slab_objects() is called.

Quoted 4 lines

online_pages() does not acquire the memory_hotplug lock. So add the missing locking there.

[ Should probably be seperated out into two patches, one for the
memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window. If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

#13 lore raw
Quoted 22 lines · David Rientjes
Quoted 9 lines · Christoph Lameter

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

Because memory hotplug is the only time s->node[] is modified after the sysfs files are created, which is the only time show_slab_objects() is called.

Quoted 4 lines

online_pages() does not acquire the memory_hotplug lock. So add the missing locking there.

Quoted 8 lines

 [ Should probably be seperated out into two patches, one for the memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window.  If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

Shouldn't [email protected] be CC-ed too ?

Bart.

#14 lore raw
Quoted 25 lines · Bart Van Assche
Quoted 24 lines · David Rientjes
Quoted 9 lines · Christoph Lameter

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

Because memory hotplug is the only time s->node[] is modified after the sysfs files are created, which is the only time show_slab_objects() is called.

Quoted 4 lines

online_pages() does not acquire the memory_hotplug lock. So add the missing locking there.

Quoted 8 lines
Quoted 6 lines

[ Should probably be seperated out into two patches, one for the
memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window. If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

Shouldn't [email protected] be CC-ed too ?

Yup, I'll add it to the patch.

#15 lore raw

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

---
 mm/memory_hotplug.c |   17 +++++++++++------
 mm/slub.c           |    4 ++--
 2 files changed, 13 insertions(+), 8 deletions(-)
mm/slub.c +2 -2
Index: linux-2.6/mm/slub.c
===================================================================
@@ -3781,7 +3781,7 @@ static ssize_t show_slab_objects(struct
 		}
 	}
 
-	down_read(&slub_lock);
+	lock_memory_hotplug();
 #ifdef CONFIG_SLUB_DEBUG
 	if (flags & SO_ALL) {
 		for_each_node_state(node, N_NORMAL_MEMORY) {
@@ -3822,7 +3822,7 @@ static ssize_t show_slab_objects(struct
 			x += sprintf(buf + x, " N%d=%lu",
 					node, nodes[node]);
 #endif
-	up_read(&slub_lock);
+	unlock_memory_hotplug();
 	kfree(nodes);
 	return x + sprintf(buf + x, "\n");
 }
reviewer Acked-by
#16 lore raw
Quoted 11 lines · Christoph Lameter

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

Quoted 7 lines

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

#17 lore raw
Quoted 13 lines · David Rientjes
Quoted 11 lines · Christoph Lameter

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

Quoted 8 lines
Quoted 7 lines

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

Is this safe to be applied without the other hotplug parts?

#18 lore raw

PATCH 1/1 one more lock on memory hotplug (Re: [PATCH] slub: Fix sysfs circular locking dependency

Quoted 20 lines · On Tue, 11 Jan 2011 08:37:29 +0200 Pekka Enberg <[email protected]> wrote:
Quoted 19 lines · David Rientjes
Quoted 17 lines · Christoph Lameter

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

Quoted 6 lines
Quoted 2 lines
Quoted 1 line

Is this safe to be applied without the other hotplug parts?

How about this ?
==
From: KAMEZAWA Hiroyuki <[email protected]>

Now, memory_hotplug_(un)lock() is used for add/remove/offline pages for avoiding races with hibernation. But this should be held in online_pages(), too. It seems asymmetric.

There are cases where one has to avoid a race with memory hotplug notifier and his own local code, and hotplug v.s. hotplug. This will add a generic solution for avoiding races. In other view, having lock here has no big impacts. online pages is tend to be done by udev script at el against each memory section one by one.

Then, it's better to have lock here, too.

---
 include/linux/memory_hotplug.h |    6 ++++++
 mm/memory_hotplug.c            |    4 ++++
 2 files changed, 10 insertions(+)
include/linux/memory_hotplug.h +6 -0
Index: linux-2.6.37.org/include/linux/memory_hotplug.h
===================================================================
@@ -161,6 +161,12 @@ extern void register_page_bootmem_info_n
 extern void put_page_bootmem(struct page *page);
 #endif
 
+/*
+ * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
+ * notifier will be called under this. 2) offline/online/add/remove memory
+ * will not run simultaneously.
+ */
+
 void lock_memory_hotplug(void);
 void unlock_memory_hotplug(void);
 
mm/memory_hotplug.c +4 -0
Index: linux-2.6.37.org/mm/memory_hotplug.c
===================================================================
@@ -407,6 +407,7 @@ int online_pages(unsigned long pfn, unsi
 	int ret;
 	struct memory_notify arg;
 
+	lock_memory_hotplug();
 	arg.start_pfn = pfn;
 	arg.nr_pages = nr_pages;
 	arg.status_change_nid = -1;
@@ -419,6 +420,7 @@ int online_pages(unsigned long pfn, unsi
 	ret = notifier_to_errno(ret);
 	if (ret) {
 		memory_notify(MEM_CANCEL_ONLINE, &arg);
+		unlock_memory_hotplug();
 		return ret;
 	}
 	/*
@@ -443,6 +445,7 @@ int online_pages(unsigned long pfn, unsi
 		printk(KERN_DEBUG "online_pages %lx at %lx failed\n",
 			nr_pages, pfn);
 		memory_notify(MEM_CANCEL_ONLINE, &arg);
+		unlock_memory_hotplug();
 		return ret;
 	}
 
@@ -467,6 +470,7 @@ int online_pages(unsigned long pfn, unsi
 
 	if (onlined_pages)
 		memory_notify(MEM_ONLINE, &arg);
+	unlock_memory_hotplug();
 
 	return 0;
 }
reviewer Acked-by on v1 1/1
#19 lore raw

Re: [PATCH] one more lock on memory hotplug (Re: [PATCH] slub: Fix sysfs circular locking dependency

Quoted 12 lines · KAMEZAWA Hiroyuki

From: KAMEZAWA Hiroyuki <[email protected]>

Now, memory_hotplug_(un)lock() is used for add/remove/offline pages for avoiding races with hibernation. But this should be held in online_pages(), too. It seems asymmetric.

There are cases where one has to avoid a race with memory hotplug notifier and his own local code, and hotplug v.s. hotplug. This will add a generic solution for avoiding races. In other view, having lock here has no big impacts. online pages is tend to be done by udev script at el against each memory section one by one.

Quoted 3 lines

Then, it's better to have lock here, too.

I think taking lock_memory_hotplug() could have been added after the initialization of the struct memory_notify, but it's not really important.

This should be targeted for 2.6.38 to avoid racing with memory hot-remove and for the pending patch in the slab tree from Christoph.

Quoted 58 lines
---
 include/linux/memory_hotplug.h |    6 ++++++
 mm/memory_hotplug.c            |    4 ++++
 2 files changed, 10 insertions(+)

Index: linux-2.6.37.org/include/linux/memory_hotplug.h
===================================================================

include/linux/memory_hotplug.h +6 -0
@@ -161,6 +161,12 @@ extern void register_page_bootmem_info_n
 extern void put_page_bootmem(struct page *page);
 #endif
 
+/*
+ * Lock for memory hotplug guarantees 1) all callbacks for memory hotplug
+ * notifier will be called under this. 2) offline/online/add/remove memory
+ * will not run simultaneously.
+ */
+
 void lock_memory_hotplug(void);
 void unlock_memory_hotplug(void);
 

Index: linux-2.6.37.org/mm/memory_hotplug.c
===================================================================

mm/memory_hotplug.c +4 -0
@@ -407,6 +407,7 @@ int online_pages(unsigned long pfn, unsi
 	int ret;
 	struct memory_notify arg;
 
+	lock_memory_hotplug();
 	arg.start_pfn = pfn;
 	arg.nr_pages = nr_pages;
 	arg.status_change_nid = -1;
@@ -419,6 +420,7 @@ int online_pages(unsigned long pfn, unsi
 	ret = notifier_to_errno(ret);
 	if (ret) {
 		memory_notify(MEM_CANCEL_ONLINE, &arg);
+		unlock_memory_hotplug();
 		return ret;
 	}
 	/*
@@ -443,6 +445,7 @@ int online_pages(unsigned long pfn, unsi
 		printk(KERN_DEBUG "online_pages %lx at %lx failed\n",
 			nr_pages, pfn);
 		memory_notify(MEM_CANCEL_ONLINE, &arg);
+		unlock_memory_hotplug();
 		return ret;
 	}
 
@@ -467,6 +470,7 @@ int online_pages(unsigned long pfn, unsi
 
 	if (onlined_pages)
 		memory_notify(MEM_ONLINE, &arg);
+	unlock_memory_hotplug();
 
 	return 0;
 }
#21 lore raw

Re: [PATCH] one more lock on memory hotplug (Re: [PATCH] slub: Fix sysfs circular locking dependency

Hi all,

I picked up both patches in slab.git in 'slub/hotplug' branch and queued them for linux-next. Andrew, just holler if you want me to send them to you; otherwise I'll send them to Linus myself.

Pekka

#22 lore raw
In reply to Pekka Enberg
Quoted 17 lines · Pekka Enberg
Quoted 17 lines
Quoted 17 lines

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

Quoted 5 lines
Quoted 2 lines
Quoted 1 line

Is this safe to be applied without the other hotplug parts?

It's safe, but not protecting anything since it can race with memory hot-add and cause inconsistent information to be displayed (since we iterate over N_NORMAL_MEMORY several times in show_slab_objects() and the memory hotplug code modifies it). I'm hoping Andrew can push Kame's patch to add lock_memory_hotplug() to online_pages() either during the merge window or during -rc1 (it has good justification -- it can race with memory hot-remove) and this can also be pushed during the rc series (to fix the lockdep warning).

#23 lore raw
Quoted 22 lines · David Rientjes
Quoted 17 lines · Pekka Enberg
Quoted 17 lines
Quoted 17 lines

New patch that just covers the slub changes.

Subject: slub: Avoid use of slub_lock in show_slab_objects()

The purpose of the locking is to prevent removal and additions of nodes when statistics are gathered for a slab cache. So we need to avoid racing with memory hotplug functionality.

It is enough to take the memory hotplug locks there instead of the slub_lock.

online_pages() currently does not acquire the memory_hotplug lock. Another patch will be submitted by the memory hotplug authors to take the memory hotplug lock and describe the uses of the memory hotplug lock to protect against adding and removal of nodes from non hotplug data structures.

Quoted 3 lines
Quoted 2 lines
Quoted 1 line

Is this safe to be applied without the other hotplug parts?

Quoted 8 lines

It's safe, but not protecting anything since it can race with memory hot-add and cause inconsistent information to be displayed (since we iterate over N_NORMAL_MEMORY several times in show_slab_objects() and the memory hotplug code modifies it). I'm hoping Andrew can push Kame's patch to add lock_memory_hotplug() to online_pages() either during the merge window or during -rc1 (it has good justification -- it can race with memory hot-remove) and this can also be pushed during the rc series (to fix the lockdep warning).

I think the two patches should go in the same batch. Andrew, do you want to pick up the slab patch as well or do you want me to pick up Kame's patch?

Pekka

#24 lore raw
In reply to David Rientjes
Quoted 6 lines · David Rientjes

 [ Should probably be seperated out into two patches, one for the memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window.  If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

Agreed.

#25 lore raw
Quoted 9 lines · Pekka Enberg
Quoted 6 lines · David Rientjes

 [ Should probably be seperated out into two patches, one for the memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window.  If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

Agreed.

Kame-san: Could you do the hotplug piece and the description of the use of the memory hotplug locks to protect extensions of data structures for new nodes?

#26 lore raw
Quoted 10 lines · On Mon, 10 Jan 2011 10:12:09 -0600 (CST) Christoph Lameter <[email protected]> wrote:
Quoted 8 lines · Pekka Enberg
Quoted 6 lines · David Rientjes

 [ Should probably be seperated out into two patches, one for the memory hotplug locking addition and one for the slub fix, both should be pushed during this merge window.  If so, a comment describing the new semantics of lock_memory_hotplug() to protect data structures that may be modified in hotplug notifier callbacks would be appreciated. ]

Quoted 5 lines
Quoted 1 line

Agreed.

Kame-san: Could you do the hotplug piece and the description of the use of the memory hotplug locks to protect extensions of data structures for new nodes?

will do.

Thanks,
-Kame