* [patch 1/9] slab: cleanup cpuup_callback()
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 15:33 ` [patch 2/9] slab: fix memory leak in cpu hotplug error path Akinobu Mita
` (7 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel
Cc: Christoph Lameter, Gautham R Shenoy, Pekka Enberg, Akinobu Mita
[-- Attachment #1: slab-refactor.patch --]
[-- Type: text/plain, Size: 9309 bytes --]
cpuup_callback() is too long.
This patch factors out CPU_UP_CANCELLED and CPU_UP_PREPARE handlings
from cpuup_callback().
Cc: Christoph Lameter <clameter@sgi.com>
Cc: Gautham R Shenoy <ego@in.ibm.com>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
mm/slab.c | 301 ++++++++++++++++++++++++++++++++------------------------------
1 file changed, 159 insertions(+), 142 deletions(-)
Index: 2.6-git/mm/slab.c
===================================================================
--- 2.6-git.orig/mm/slab.c
+++ 2.6-git/mm/slab.c
@@ -1156,105 +1156,181 @@ static inline int cache_free_alien(struc
}
#endif
-static int __cpuinit cpuup_callback(struct notifier_block *nfb,
- unsigned long action, void *hcpu)
+static void __cpuinit cpuup_canceled(long cpu)
+{
+ struct kmem_cache *cachep;
+ struct kmem_list3 *l3 = NULL;
+ int node = cpu_to_node(cpu);
+
+ list_for_each_entry(cachep, &cache_chain, next) {
+ struct array_cache *nc;
+ struct array_cache *shared;
+ struct array_cache **alien;
+ cpumask_t mask;
+
+ mask = node_to_cpumask(node);
+ /* cpu is dead; no one can alloc from it. */
+ nc = cachep->array[cpu];
+ cachep->array[cpu] = NULL;
+ l3 = cachep->nodelists[node];
+
+ if (!l3)
+ goto free_array_cache;
+
+ spin_lock_irq(&l3->list_lock);
+
+ /* Free limit for this kmem_list3 */
+ l3->free_limit -= cachep->batchcount;
+ if (nc)
+ free_block(cachep, nc->entry, nc->avail, node);
+
+ if (!cpus_empty(mask)) {
+ spin_unlock_irq(&l3->list_lock);
+ goto free_array_cache;
+ }
+
+ shared = l3->shared;
+ if (shared) {
+ free_block(cachep, shared->entry,
+ shared->avail, node);
+ l3->shared = NULL;
+ }
+
+ alien = l3->alien;
+ l3->alien = NULL;
+
+ spin_unlock_irq(&l3->list_lock);
+
+ kfree(shared);
+ if (alien) {
+ drain_alien_cache(cachep, alien);
+ free_alien_cache(alien);
+ }
+free_array_cache:
+ kfree(nc);
+ }
+ /*
+ * In the previous loop, all the objects were freed to
+ * the respective cache's slabs, now we can go ahead and
+ * shrink each nodelist to its limit.
+ */
+ list_for_each_entry(cachep, &cache_chain, next) {
+ l3 = cachep->nodelists[node];
+ if (!l3)
+ continue;
+ drain_freelist(cachep, l3, l3->free_objects);
+ }
+}
+
+static int __cpuinit cpuup_prepare(long cpu)
{
- long cpu = (long)hcpu;
struct kmem_cache *cachep;
struct kmem_list3 *l3 = NULL;
int node = cpu_to_node(cpu);
const int memsize = sizeof(struct kmem_list3);
- switch (action) {
- case CPU_LOCK_ACQUIRE:
- mutex_lock(&cache_chain_mutex);
- break;
- case CPU_UP_PREPARE:
- case CPU_UP_PREPARE_FROZEN:
+ /*
+ * We need to do this right in the beginning since
+ * alloc_arraycache's are going to use this list.
+ * kmalloc_node allows us to add the slab to the right
+ * kmem_list3 and not this cpu's kmem_list3
+ */
+
+ list_for_each_entry(cachep, &cache_chain, next) {
/*
- * We need to do this right in the beginning since
- * alloc_arraycache's are going to use this list.
- * kmalloc_node allows us to add the slab to the right
- * kmem_list3 and not this cpu's kmem_list3
+ * Set up the size64 kmemlist for cpu before we can
+ * begin anything. Make sure some other cpu on this
+ * node has not already allocated this
*/
+ if (!cachep->nodelists[node]) {
+ l3 = kmalloc_node(memsize, GFP_KERNEL, node);
+ if (!l3)
+ goto bad;
+ kmem_list3_init(l3);
+ l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
+ ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
- list_for_each_entry(cachep, &cache_chain, next) {
/*
- * Set up the size64 kmemlist for cpu before we can
- * begin anything. Make sure some other cpu on this
- * node has not already allocated this
+ * The l3s don't come and go as CPUs come and
+ * go. cache_chain_mutex is sufficient
+ * protection here.
*/
- if (!cachep->nodelists[node]) {
- l3 = kmalloc_node(memsize, GFP_KERNEL, node);
- if (!l3)
- goto bad;
- kmem_list3_init(l3);
- l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
- ((unsigned long)cachep) % REAPTIMEOUT_LIST3;
-
- /*
- * The l3s don't come and go as CPUs come and
- * go. cache_chain_mutex is sufficient
- * protection here.
- */
- cachep->nodelists[node] = l3;
- }
-
- spin_lock_irq(&cachep->nodelists[node]->list_lock);
- cachep->nodelists[node]->free_limit =
- (1 + nr_cpus_node(node)) *
- cachep->batchcount + cachep->num;
- spin_unlock_irq(&cachep->nodelists[node]->list_lock);
+ cachep->nodelists[node] = l3;
}
- /*
- * Now we can go ahead with allocating the shared arrays and
- * array caches
- */
- list_for_each_entry(cachep, &cache_chain, next) {
- struct array_cache *nc;
- struct array_cache *shared = NULL;
- struct array_cache **alien = NULL;
+ spin_lock_irq(&cachep->nodelists[node]->list_lock);
+ cachep->nodelists[node]->free_limit =
+ (1 + nr_cpus_node(node)) *
+ cachep->batchcount + cachep->num;
+ spin_unlock_irq(&cachep->nodelists[node]->list_lock);
+ }
- nc = alloc_arraycache(node, cachep->limit,
- cachep->batchcount);
- if (!nc)
+ /*
+ * Now we can go ahead with allocating the shared arrays and
+ * array caches
+ */
+ list_for_each_entry(cachep, &cache_chain, next) {
+ struct array_cache *nc;
+ struct array_cache *shared = NULL;
+ struct array_cache **alien = NULL;
+
+ nc = alloc_arraycache(node, cachep->limit,
+ cachep->batchcount);
+ if (!nc)
+ goto bad;
+ if (cachep->shared) {
+ shared = alloc_arraycache(node,
+ cachep->shared * cachep->batchcount,
+ 0xbaadf00d);
+ if (!shared)
goto bad;
- if (cachep->shared) {
- shared = alloc_arraycache(node,
- cachep->shared * cachep->batchcount,
- 0xbaadf00d);
- if (!shared)
- goto bad;
- }
- if (use_alien_caches) {
- alien = alloc_alien_cache(node, cachep->limit);
- if (!alien)
- goto bad;
- }
- cachep->array[cpu] = nc;
- l3 = cachep->nodelists[node];
- BUG_ON(!l3);
+ }
+ if (use_alien_caches) {
+ alien = alloc_alien_cache(node, cachep->limit);
+ if (!alien)
+ goto bad;
+ }
+ cachep->array[cpu] = nc;
+ l3 = cachep->nodelists[node];
+ BUG_ON(!l3);
- spin_lock_irq(&l3->list_lock);
- if (!l3->shared) {
- /*
- * We are serialised from CPU_DEAD or
- * CPU_UP_CANCELLED by the cpucontrol lock
- */
- l3->shared = shared;
- shared = NULL;
- }
+ spin_lock_irq(&l3->list_lock);
+ if (!l3->shared) {
+ /*
+ * We are serialised from CPU_DEAD or
+ * CPU_UP_CANCELLED by the cpucontrol lock
+ */
+ l3->shared = shared;
+ shared = NULL;
+ }
#ifdef CONFIG_NUMA
- if (!l3->alien) {
- l3->alien = alien;
- alien = NULL;
- }
-#endif
- spin_unlock_irq(&l3->list_lock);
- kfree(shared);
- free_alien_cache(alien);
+ if (!l3->alien) {
+ l3->alien = alien;
+ alien = NULL;
}
+#endif
+ spin_unlock_irq(&l3->list_lock);
+ kfree(shared);
+ free_alien_cache(alien);
+ }
+ return 0;
+bad:
+ return -ENOMEM;
+}
+
+static int __cpuinit cpuup_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ long cpu = (long)hcpu;
+ int err = 0;
+
+ switch (action) {
+ case CPU_LOCK_ACQUIRE:
+ mutex_lock(&cache_chain_mutex);
+ break;
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ err = cpuup_prepare(cpu);
break;
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
@@ -1291,72 +1367,13 @@ static int __cpuinit cpuup_callback(stru
#endif
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
- list_for_each_entry(cachep, &cache_chain, next) {
- struct array_cache *nc;
- struct array_cache *shared;
- struct array_cache **alien;
- cpumask_t mask;
-
- mask = node_to_cpumask(node);
- /* cpu is dead; no one can alloc from it. */
- nc = cachep->array[cpu];
- cachep->array[cpu] = NULL;
- l3 = cachep->nodelists[node];
-
- if (!l3)
- goto free_array_cache;
-
- spin_lock_irq(&l3->list_lock);
-
- /* Free limit for this kmem_list3 */
- l3->free_limit -= cachep->batchcount;
- if (nc)
- free_block(cachep, nc->entry, nc->avail, node);
-
- if (!cpus_empty(mask)) {
- spin_unlock_irq(&l3->list_lock);
- goto free_array_cache;
- }
-
- shared = l3->shared;
- if (shared) {
- free_block(cachep, shared->entry,
- shared->avail, node);
- l3->shared = NULL;
- }
-
- alien = l3->alien;
- l3->alien = NULL;
-
- spin_unlock_irq(&l3->list_lock);
-
- kfree(shared);
- if (alien) {
- drain_alien_cache(cachep, alien);
- free_alien_cache(alien);
- }
-free_array_cache:
- kfree(nc);
- }
- /*
- * In the previous loop, all the objects were freed to
- * the respective cache's slabs, now we can go ahead and
- * shrink each nodelist to its limit.
- */
- list_for_each_entry(cachep, &cache_chain, next) {
- l3 = cachep->nodelists[node];
- if (!l3)
- continue;
- drain_freelist(cachep, l3, l3->free_objects);
- }
+ cpuup_canceled(cpu);
break;
case CPU_LOCK_RELEASE:
mutex_unlock(&cache_chain_mutex);
break;
}
- return NOTIFY_OK;
-bad:
- return NOTIFY_BAD;
+ return err ? NOTIFY_BAD : NOTIFY_OK;
}
static struct notifier_block __cpuinitdata cpucache_notifier = {
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 2/9] slab: fix memory leak in cpu hotplug error path
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
2007-07-22 15:33 ` [patch 1/9] slab: cleanup cpuup_callback() Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-24 9:46 ` Pekka Enberg
2007-07-22 15:33 ` [patch 3/9] cpu: deliver CPU_UP_CANCELED only to NOTIFY_OKed callbacks with CPU_UP_PREPARE Akinobu Mita
` (6 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel
Cc: Christoph Lameter, Gautham R Shenoy, Pekka Enberg, Akinobu Mita
[-- Attachment #1: slab-cpuhotplug-memleak-fixes.patch --]
[-- Type: text/plain, Size: 1179 bytes --]
This patch fixes memory leak in error path.
In reality, we don't need to call cpuup_canceled(cpu) for now.
But upcoming cpu hotplug error handling change needs this.
Cc: Christoph Lameter <clameter@sgi.com>
Cc: Gautham R Shenoy <ego@in.ibm.com>
Cc: Pekka Enberg <penberg@cs.helsinki.fi>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
mm/slab.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
Index: 2.6-git/mm/slab.c
===================================================================
--- 2.6-git.orig/mm/slab.c
+++ 2.6-git/mm/slab.c
@@ -1282,13 +1282,18 @@ static int __cpuinit cpuup_prepare(long
shared = alloc_arraycache(node,
cachep->shared * cachep->batchcount,
0xbaadf00d);
- if (!shared)
+ if (!shared) {
+ kfree(nc);
goto bad;
+ }
}
if (use_alien_caches) {
alien = alloc_alien_cache(node, cachep->limit);
- if (!alien)
+ if (!alien) {
+ kfree(shared);
+ kfree(nc);
goto bad;
+ }
}
cachep->array[cpu] = nc;
l3 = cachep->nodelists[node];
@@ -1315,6 +1320,7 @@ static int __cpuinit cpuup_prepare(long
}
return 0;
bad:
+ cpuup_canceled(cpu);
return -ENOMEM;
}
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 3/9] cpu: deliver CPU_UP_CANCELED only to NOTIFY_OKed callbacks with CPU_UP_PREPARE
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
2007-07-22 15:33 ` [patch 1/9] slab: cleanup cpuup_callback() Akinobu Mita
2007-07-22 15:33 ` [patch 2/9] slab: fix memory leak in cpu hotplug error path Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 23:48 ` Rusty Russell
2007-07-22 15:33 ` [patch 4/9] topology: remove topology_dev_map Akinobu Mita
` (5 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel
Cc: Rusty Russell, Greg Kroah-Hartman, Dmitriy Zavin, H. Peter Anvin,
Andi Kleen, Ashok Raj, Akinobu Mita
[-- Attachment #1: cpuhotplug-nr-calls.patch --]
[-- Type: text/plain, Size: 2349 bytes --]
From: Akinobu Mita <akinobu.mita@gmail.com>
The functions in a CPU notifier chain is called with CPU_UP_PREPARE event
before making the CPU online. If one of the callback returns NOTIFY_BAD,
it stops to deliver CPU_UP_PREPARE event, and CPU online operation is canceled.
Then CPU_UP_CANCELED event is delivered to the functions in a CPU notifier
chain again.
This CPU_UP_CANCELED event is delivered to the functions which have been
called with CPU_UP_PREPARE, not delivered to the functions which haven't
been called with CPU_UP_PREPARE.
The problem that makes existing cpu hotplug error handlings complex is
that the CPU_UP_CANCELED event is delivered to the function that has
returned NOTIFY_BAD, too.
Usually we don't expect to call destructor function against the
object that has failed to initialize. It is like:
err = register_something();
if (err) {
unregister_something();
return err;
}
So it is natural to deliver CPU_UP_CANCELED event only to the functions
that have returned NOTIFY_OK with CPU_UP_PREPARE event and not to call
the function that have returned NOTIFY_BAD. This is what this patch is doing.
Otherwise, every cpu hotplug notifiler has to track whether
notifiler event is failed or not for each cpu.
(drivers/base/topology.c is doing this with topology_dev_map)
Similary this patch makes same thing with CPU_DOWN_PREPARE and
CPU_DOWN_FAILED evnets.
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
kernel/cpu.c | 2 ++
1 file changed, 2 insertions(+)
Index: 2.6-git/kernel/cpu.c
===================================================================
--- 2.6-git.orig/kernel/cpu.c
+++ 2.6-git/kernel/cpu.c
@@ -150,6 +150,7 @@ static int _cpu_down(unsigned int cpu, i
err = __raw_notifier_call_chain(&cpu_chain, CPU_DOWN_PREPARE | mod,
hcpu, -1, &nr_calls);
if (err == NOTIFY_BAD) {
+ nr_calls--;
__raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
hcpu, nr_calls, NULL);
printk("%s: attempt to take down CPU %u failed\n",
@@ -233,6 +234,7 @@ static int __cpuinit _cpu_up(unsigned in
ret = __raw_notifier_call_chain(&cpu_chain, CPU_UP_PREPARE | mod, hcpu,
-1, &nr_calls);
if (ret == NOTIFY_BAD) {
+ nr_calls--;
printk("%s: attempt to bring up CPU %u failed\n",
__FUNCTION__, cpu);
ret = -EINVAL;
--
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [patch 3/9] cpu: deliver CPU_UP_CANCELED only to NOTIFY_OKed callbacks with CPU_UP_PREPARE
2007-07-22 15:33 ` [patch 3/9] cpu: deliver CPU_UP_CANCELED only to NOTIFY_OKed callbacks with CPU_UP_PREPARE Akinobu Mita
@ 2007-07-22 23:48 ` Rusty Russell
0 siblings, 0 replies; 13+ messages in thread
From: Rusty Russell @ 2007-07-22 23:48 UTC (permalink / raw)
To: Akinobu Mita
Cc: linux-kernel, Greg Kroah-Hartman, Dmitriy Zavin, H. Peter Anvin,
Andi Kleen, Ashok Raj
On Mon, 2007-07-23 at 00:33 +0900, Akinobu Mita wrote:
> plain text document attachment (cpuhotplug-nr-calls.patch)
> From: Akinobu Mita <akinobu.mita@gmail.com>
>
> The functions in a CPU notifier chain is called with CPU_UP_PREPARE event
> before making the CPU online. If one of the callback returns NOTIFY_BAD,
> it stops to deliver CPU_UP_PREPARE event, and CPU online operation is canceled.
> Then CPU_UP_CANCELED event is delivered to the functions in a CPU notifier
> chain again.
>
> This CPU_UP_CANCELED event is delivered to the functions which have been
> called with CPU_UP_PREPARE, not delivered to the functions which haven't
> been called with CPU_UP_PREPARE.
>
> The problem that makes existing cpu hotplug error handlings complex is
> that the CPU_UP_CANCELED event is delivered to the function that has
> returned NOTIFY_BAD, too.
>
> Usually we don't expect to call destructor function against the
> object that has failed to initialize. It is like:
>
> err = register_something();
> if (err) {
> unregister_something();
> return err;
> }
>
> So it is natural to deliver CPU_UP_CANCELED event only to the functions
> that have returned NOTIFY_OK with CPU_UP_PREPARE event and not to call
> the function that have returned NOTIFY_BAD. This is what this patch is doing.
>
> Otherwise, every cpu hotplug notifiler has to track whether
> notifiler event is failed or not for each cpu.
> (drivers/base/topology.c is doing this with topology_dev_map)
>
> Similary this patch makes same thing with CPU_DOWN_PREPARE and
> CPU_DOWN_FAILED evnets.
>
> Cc: Rusty Russell <rusty@rustcorp.com.au>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
This makes a great deal of sense; I consider it a bugfix.
Thanks!
Rusty.
^ permalink raw reply [flat|nested] 13+ messages in thread
* [patch 4/9] topology: remove topology_dev_map
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (2 preceding siblings ...)
2007-07-22 15:33 ` [patch 3/9] cpu: deliver CPU_UP_CANCELED only to NOTIFY_OKed callbacks with CPU_UP_PREPARE Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-23 23:16 ` Greg KH
2007-07-22 15:33 ` [patch 5/9] thermal_throttle: fix cpu hotplug error handling Akinobu Mita
` (4 subsequent siblings)
8 siblings, 1 reply; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: Greg Kroah-Hartman, Akinobu Mita
[-- Attachment #1: topology-cpuhotplug-cleanup.patch --]
[-- Type: text/plain, Size: 1292 bytes --]
By previous cpu hotplug notifier change, we don't need to track
topology_dev existence for each cpu by topology_dev_map.
Cc: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
drivers/base/topology.c | 11 +----------
1 file changed, 1 insertion(+), 10 deletions(-)
Index: 2.6-git/drivers/base/topology.c
===================================================================
--- 2.6-git.orig/drivers/base/topology.c
+++ 2.6-git/drivers/base/topology.c
@@ -94,27 +94,18 @@ static struct attribute_group topology_a
.name = "topology"
};
-static cpumask_t topology_dev_map = CPU_MASK_NONE;
-
/* Add/Remove cpu_topology interface for CPU device */
static int __cpuinit topology_add_dev(unsigned int cpu)
{
- int rc;
struct sys_device *sys_dev = get_cpu_sysdev(cpu);
- rc = sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
- if (!rc)
- cpu_set(cpu, topology_dev_map);
- return rc;
+ return sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
}
static void __cpuinit topology_remove_dev(unsigned int cpu)
{
struct sys_device *sys_dev = get_cpu_sysdev(cpu);
- if (!cpu_isset(cpu, topology_dev_map))
- return;
- cpu_clear(cpu, topology_dev_map);
sysfs_remove_group(&sys_dev->kobj, &topology_attr_group);
}
--
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [patch 4/9] topology: remove topology_dev_map
2007-07-22 15:33 ` [patch 4/9] topology: remove topology_dev_map Akinobu Mita
@ 2007-07-23 23:16 ` Greg KH
0 siblings, 0 replies; 13+ messages in thread
From: Greg KH @ 2007-07-23 23:16 UTC (permalink / raw)
To: Akinobu Mita; +Cc: linux-kernel
On Mon, Jul 23, 2007 at 12:33:16AM +0900, Akinobu Mita wrote:
> By previous cpu hotplug notifier change, we don't need to track
> topology_dev existence for each cpu by topology_dev_map.
>
> Cc: Greg Kroah-Hartman <gregkh@suse.de>
> Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
I'm guessing that this is going to have to go in through some other tree
than mine, so feel free to add:
Acked-by: Greg Kroah-Hartman <gregkh@suse.de>
to it.
thanks,
greg k-h
^ permalink raw reply [flat|nested] 13+ messages in thread
* [patch 5/9] thermal_throttle: fix cpu hotplug error handling
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (3 preceding siblings ...)
2007-07-22 15:33 ` [patch 4/9] topology: remove topology_dev_map Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 15:33 ` [patch 6/9] msr: " Akinobu Mita
` (3 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: Dmitriy Zavin, Akinobu Mita
[-- Attachment #1: therm_throt-hotplug.patch --]
[-- Type: text/plain, Size: 1341 bytes --]
Do thermal_throttle_add_dev() in CPU_UP_PREPARE instead of CPU_ONLINE.
Cc: Dmitriy Zavin <dmitriyz@google.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
arch/i386/kernel/cpu/mcheck/therm_throt.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
Index: 2.6-git/arch/i386/kernel/cpu/mcheck/therm_throt.c
===================================================================
--- 2.6-git.orig/arch/i386/kernel/cpu/mcheck/therm_throt.c
+++ 2.6-git/arch/i386/kernel/cpu/mcheck/therm_throt.c
@@ -131,17 +131,19 @@ static __cpuinit int thermal_throttle_cp
{
unsigned int cpu = (unsigned long)hcpu;
struct sys_device *sys_dev;
- int err;
+ int err = 0;
sys_dev = get_cpu_sysdev(cpu);
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
mutex_lock(&therm_cpu_lock);
err = thermal_throttle_add_dev(sys_dev);
mutex_unlock(&therm_cpu_lock);
WARN_ON(err);
break;
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
mutex_lock(&therm_cpu_lock);
@@ -149,7 +151,7 @@ static __cpuinit int thermal_throttle_cp
mutex_unlock(&therm_cpu_lock);
break;
}
- return NOTIFY_OK;
+ return err ? NOTIFY_BAD : NOTIFY_OK;
}
static struct notifier_block thermal_throttle_cpu_notifier =
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 6/9] msr: fix cpu hotplug error handling
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (4 preceding siblings ...)
2007-07-22 15:33 ` [patch 5/9] thermal_throttle: fix cpu hotplug error handling Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 15:33 ` [patch 7/9] cpuid: " Akinobu Mita
` (2 subsequent siblings)
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: H. Peter Anvin, Akinobu Mita
[-- Attachment #1: msr-cpuhotplug.patch --]
[-- Type: text/plain, Size: 2271 bytes --]
Do msr_device_create() in CPU_UP_PREPARE instead of CPU_ONLINE.
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
arch/i386/kernel/msr.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
Index: 2.6-git/arch/i386/kernel/msr.c
===================================================================
--- 2.6-git.orig/arch/i386/kernel/msr.c
+++ 2.6-git/arch/i386/kernel/msr.c
@@ -135,33 +135,39 @@ static const struct file_operations msr_
.open = msr_open,
};
-static int msr_device_create(int i)
+static int msr_device_create(int cpu)
{
- int err = 0;
struct device *dev;
- dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, i), "msr%d",i);
- if (IS_ERR(dev))
- err = PTR_ERR(dev);
- return err;
+ dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu),
+ "msr%d", cpu);
+ return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+
+static void msr_device_destroy(int cpu)
+{
+ device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
}
static int msr_class_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ int err = 0;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- msr_device_create(cpu);
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ err = msr_device_create(cpu);
break;
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
+ msr_device_destroy(cpu);
break;
}
- return NOTIFY_OK;
+ return err ? NOTIFY_BAD : NOTIFY_OK;
}
static struct notifier_block __cpuinitdata msr_class_cpu_notifier =
@@ -198,7 +204,7 @@ static int __init msr_init(void)
out_class:
i = 0;
for_each_online_cpu(i)
- device_destroy(msr_class, MKDEV(MSR_MAJOR, i));
+ msr_device_destroy(i);
class_destroy(msr_class);
out_chrdev:
unregister_chrdev(MSR_MAJOR, "cpu/msr");
@@ -210,7 +216,7 @@ static void __exit msr_exit(void)
{
int cpu = 0;
for_each_online_cpu(cpu)
- device_destroy(msr_class, MKDEV(MSR_MAJOR, cpu));
+ msr_device_destroy(cpu);
class_destroy(msr_class);
unregister_chrdev(MSR_MAJOR, "cpu/msr");
unregister_hotcpu_notifier(&msr_class_cpu_notifier);
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 7/9] cpuid: fix cpu hotplug error handling
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (5 preceding siblings ...)
2007-07-22 15:33 ` [patch 6/9] msr: " Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 15:33 ` [patch 8/9] mce: " Akinobu Mita
2007-07-22 15:33 ` [patch 9/9] intel_cacheinfo: " Akinobu Mita
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: H. Peter Anvin, Akinobu Mita
[-- Attachment #1: cpuid-cpuhotplug.patch --]
[-- Type: text/plain, Size: 2298 bytes --]
Do cpuid_device_create() in CPU_UP_PREPARE instead of CPU_ONLINE.
Cc: "H. Peter Anvin" <hpa@zytor.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
arch/i386/kernel/cpuid.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
Index: 2.6-git/arch/i386/kernel/cpuid.c
===================================================================
--- 2.6-git.orig/arch/i386/kernel/cpuid.c
+++ 2.6-git/arch/i386/kernel/cpuid.c
@@ -152,32 +152,38 @@ static const struct file_operations cpui
.open = cpuid_open,
};
-static int cpuid_device_create(int i)
+static int cpuid_device_create(int cpu)
{
- int err = 0;
struct device *dev;
- dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, i), "cpu%d",i);
- if (IS_ERR(dev))
- err = PTR_ERR(dev);
- return err;
+ dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu),
+ "cpu%d", cpu);
+ return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+}
+
+static void cpuid_device_destroy(int cpu)
+{
+ device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
}
static int cpuid_class_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ int err = 0;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- cpuid_device_create(cpu);
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ err = cpuid_device_create(cpu);
break;
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
- device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
+ cpuid_device_destroy(cpu);
break;
}
- return NOTIFY_OK;
+ return err ? NOTIFY_BAD : NOTIFY_OK;
}
static struct notifier_block __cpuinitdata cpuid_class_cpu_notifier =
@@ -214,7 +220,7 @@ static int __init cpuid_init(void)
out_class:
i = 0;
for_each_online_cpu(i) {
- device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, i));
+ cpuid_device_destroy(i);
}
class_destroy(cpuid_class);
out_chrdev:
@@ -228,7 +234,7 @@ static void __exit cpuid_exit(void)
int cpu = 0;
for_each_online_cpu(cpu)
- device_destroy(cpuid_class, MKDEV(CPUID_MAJOR, cpu));
+ cpuid_device_destroy(cpu);
class_destroy(cpuid_class);
unregister_chrdev(CPUID_MAJOR, "cpu/cpuid");
unregister_hotcpu_notifier(&cpuid_class_cpu_notifier);
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 8/9] mce: fix cpu hotplug error handling
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (6 preceding siblings ...)
2007-07-22 15:33 ` [patch 7/9] cpuid: " Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
2007-07-22 15:33 ` [patch 9/9] intel_cacheinfo: " Akinobu Mita
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: Andi Kleen, Akinobu Mita
[-- Attachment #1: mce-cpuhotplug.patch --]
[-- Type: text/plain, Size: 3023 bytes --]
- Clear kobject in percpu device_mce before calling sysdev_register() with
Because mce_create_device() may fail and it leaves kobject filled with
junk. It will be the problem when mce_create_device() will be called
next time.
- Fix error handling in mce_create_device()
Error handling should not do sysdev_remove_file() with not yet added
attributes.
- Don't register hotcpu notifier when mce_create_device() returns error
- Do mce_create_device() in CPU_UP_PREPARE instead of CPU_ONLINE
Cc: Andi Kleen <andi@firstfloor.org>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
arch/x86_64/kernel/mce.c | 39 +++++++++++++++++++++++++++++----------
1 file changed, 29 insertions(+), 10 deletions(-)
Index: 2.6-git/arch/x86_64/kernel/mce.c
===================================================================
--- 2.6-git.orig/arch/x86_64/kernel/mce.c
+++ 2.6-git/arch/x86_64/kernel/mce.c
@@ -690,16 +690,29 @@ static __cpuinit int mce_create_device(u
if (!mce_available(&cpu_data[cpu]))
return -EIO;
+ memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
per_cpu(device_mce,cpu).id = cpu;
per_cpu(device_mce,cpu).cls = &mce_sysclass;
err = sysdev_register(&per_cpu(device_mce,cpu));
+ if (err)
+ return err;
+
+ for (i = 0; mce_attributes[i]; i++) {
+ err = sysdev_create_file(&per_cpu(device_mce,cpu),
+ mce_attributes[i]);
+ if (err)
+ goto error;
+ }
- if (!err) {
- for (i = 0; mce_attributes[i]; i++)
- sysdev_create_file(&per_cpu(device_mce,cpu),
- mce_attributes[i]);
+ return 0;
+error:
+ while (i--) {
+ sysdev_remove_file(&per_cpu(device_mce,cpu),
+ mce_attributes[i]);
}
+ sysdev_unregister(&per_cpu(device_mce,cpu));
+
return err;
}
@@ -711,7 +724,6 @@ static void mce_remove_device(unsigned i
sysdev_remove_file(&per_cpu(device_mce,cpu),
mce_attributes[i]);
sysdev_unregister(&per_cpu(device_mce,cpu));
- memset(&per_cpu(device_mce, cpu).kobj, 0, sizeof(struct kobject));
}
/* Get notified when a cpu comes on/off. Be hotplug friendly. */
@@ -719,18 +731,21 @@ static int
mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
+ int err = 0;
switch (action) {
- case CPU_ONLINE:
- case CPU_ONLINE_FROZEN:
- mce_create_device(cpu);
+ case CPU_UP_PREPARE:
+ case CPU_UP_PREPARE_FROZEN:
+ err = mce_create_device(cpu);
break;
+ case CPU_UP_CANCELED:
+ case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
mce_remove_device(cpu);
break;
}
- return NOTIFY_OK;
+ return err ? NOTIFY_BAD : NOTIFY_OK;
}
static struct notifier_block mce_cpu_notifier = {
@@ -745,9 +760,13 @@ static __init int mce_init_device(void)
if (!mce_available(&boot_cpu_data))
return -EIO;
err = sysdev_class_register(&mce_sysclass);
+ if (err)
+ return err;
for_each_online_cpu(i) {
- mce_create_device(i);
+ err = mce_create_device(i);
+ if (err)
+ return err;
}
register_hotcpu_notifier(&mce_cpu_notifier);
--
^ permalink raw reply [flat|nested] 13+ messages in thread* [patch 9/9] intel_cacheinfo: fix cpu hotplug error handling
2007-07-22 15:33 [patch 0/9] CPU hotplug error handling fixes take2 Akinobu Mita
` (7 preceding siblings ...)
2007-07-22 15:33 ` [patch 8/9] mce: " Akinobu Mita
@ 2007-07-22 15:33 ` Akinobu Mita
8 siblings, 0 replies; 13+ messages in thread
From: Akinobu Mita @ 2007-07-22 15:33 UTC (permalink / raw)
To: linux-kernel; +Cc: Ashok Raj, Akinobu Mita
[-- Attachment #1: intel-cacheinfo-cpu-hotplug.patch --]
[-- Type: text/plain, Size: 5042 bytes --]
- Fix resource leakage in error case within detect_cache_attributes()
- Don't register hotcpu notifier when cache_add_dev() returns error
- Introduce cache_dev_map cpumask to track whether cache interface for
CPU is successfully added by cache_add_dev() or not.
cache_add_dev() may fail with out of memory error. In order to
avoid cache_remove_dev() with that uninitialized cache interface when
CPU_DEAD event is delivered we need to have the cache_dev_map cpumask.
(We cannot change cache_add_dev() from CPU_ONLINE event handler
to CPU_UP_PREPARE event handler. Because cache_add_dev() needs
to do cpuid and store the results with its CPU online.)
Cc: Ashok Raj <ashok.raj@intel.com>
Signed-off-by: Akinobu Mita <akinobu.mita@gmail.com>
---
arch/i386/kernel/cpu/intel_cacheinfo.c | 64 +++++++++++++++++++++++----------
1 file changed, 45 insertions(+), 19 deletions(-)
Index: 2.6-git/arch/i386/kernel/cpu/intel_cacheinfo.c
===================================================================
--- 2.6-git.orig/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ 2.6-git/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -466,6 +466,11 @@ static void __init cache_remove_shared_c
static void free_cache_attributes(unsigned int cpu)
{
+ int i;
+
+ for (i = 0; i < num_cache_leaves; i++)
+ cache_remove_shared_cpu_map(cpu, i);
+
kfree(cpuid4_info[cpu]);
cpuid4_info[cpu] = NULL;
}
@@ -473,8 +478,8 @@ static void free_cache_attributes(unsign
static int __cpuinit detect_cache_attributes(unsigned int cpu)
{
struct _cpuid4_info *this_leaf;
- unsigned long j;
- int retval;
+ unsigned long j;
+ int retval;
cpumask_t oldmask;
if (num_cache_leaves == 0)
@@ -491,19 +496,26 @@ static int __cpuinit detect_cache_attrib
goto out;
/* Do cpuid and store the results */
- retval = 0;
for (j = 0; j < num_cache_leaves; j++) {
this_leaf = CPUID4_INFO_IDX(cpu, j);
retval = cpuid4_cache_lookup(j, this_leaf);
- if (unlikely(retval < 0))
+ if (unlikely(retval < 0)) {
+ int i;
+
+ for (i = 0; i < j; i++)
+ cache_remove_shared_cpu_map(cpu, i);
break;
+ }
cache_shared_cpu_map_setup(cpu, j);
}
set_cpus_allowed(current, oldmask);
out:
- if (retval)
- free_cache_attributes(cpu);
+ if (retval) {
+ kfree(cpuid4_info[cpu]);
+ cpuid4_info[cpu] = NULL;
+ }
+
return retval;
}
@@ -647,13 +659,14 @@ static void cpuid4_cache_sysfs_exit(unsi
static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
{
+ int err;
if (num_cache_leaves == 0)
return -ENOENT;
- detect_cache_attributes(cpu);
- if (cpuid4_info[cpu] == NULL)
- return -ENOENT;
+ err = detect_cache_attributes(cpu);
+ if (err)
+ return err;
/* Allocate all required memory */
cache_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
@@ -672,13 +685,15 @@ err_out:
return -ENOMEM;
}
+static cpumask_t cache_dev_map = CPU_MASK_NONE;
+
/* Add/Remove cache interface for CPU device */
static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
{
unsigned int cpu = sys_dev->id;
unsigned long i, j;
struct _index_kobject *this_object;
- int retval = 0;
+ int retval;
retval = cpuid4_cache_sysfs_init(cpu);
if (unlikely(retval < 0))
@@ -688,6 +703,10 @@ static int __cpuinit cache_add_dev(struc
kobject_set_name(cache_kobject[cpu], "%s", "cache");
cache_kobject[cpu]->ktype = &ktype_percpu_entry;
retval = kobject_register(cache_kobject[cpu]);
+ if (retval < 0) {
+ cpuid4_cache_sysfs_exit(cpu);
+ return retval;
+ }
for (i = 0; i < num_cache_leaves; i++) {
this_object = INDEX_KOBJECT_PTR(cpu,i);
@@ -707,6 +726,9 @@ static int __cpuinit cache_add_dev(struc
break;
}
}
+ if (!retval)
+ cpu_set(cpu, cache_dev_map);
+
return retval;
}
@@ -715,13 +737,14 @@ static void __cpuexit cache_remove_dev(s
unsigned int cpu = sys_dev->id;
unsigned long i;
- for (i = 0; i < num_cache_leaves; i++) {
- cache_remove_shared_cpu_map(cpu, i);
+ if (!cpu_isset(cpu, cache_dev_map))
+ return;
+ cpu_clear(cpu, cache_dev_map);
+
+ for (i = 0; i < num_cache_leaves; i++)
kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
- }
kobject_unregister(cache_kobject[cpu]);
cpuid4_cache_sysfs_exit(cpu);
- return;
}
static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
@@ -746,7 +769,7 @@ static int __cpuinit cacheinfo_cpu_callb
static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier =
{
- .notifier_call = cacheinfo_cpu_callback,
+ .notifier_call = cacheinfo_cpu_callback,
};
static int __cpuinit cache_sysfs_init(void)
@@ -756,12 +779,15 @@ static int __cpuinit cache_sysfs_init(vo
if (num_cache_leaves == 0)
return 0;
- register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-
for_each_online_cpu(i) {
- cacheinfo_cpu_callback(&cacheinfo_cpu_notifier, CPU_ONLINE,
- (void *)(long)i);
+ int err;
+ struct sys_device *sys_dev = get_cpu_sysdev(i);
+
+ err = cache_add_dev(sys_dev);
+ if (err)
+ return err;
}
+ register_hotcpu_notifier(&cacheinfo_cpu_notifier);
return 0;
}
--
^ permalink raw reply [flat|nested] 13+ messages in thread