提交 51888ca2 编写于 作者: S Srivatsa Vaddagiri 提交者: Linus Torvalds

[PATCH] sched_domain: handle kmalloc failure

Try to handle mem allocation failures in build_sched_domains by bailing out
and cleaning up thus-far allocated memory.  The patch has a direct consequence
that we disable load balancing completely (even at sibling level) upon *any*
memory allocation failure.

[Lee.Schermerhorn@hp.com: bugfix]
Signed-off-by: NSrivatsa Vaddagir <vatsa@in.ibm.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: "Siddha, Suresh B" <suresh.b.siddha@intel.com>
Signed-off-by: NLee Schermerhorn <lee.schermerhorn@hp.com>
Signed-off-by: NAndrew Morton <akpm@osdl.org>
Signed-off-by: NLinus Torvalds <torvalds@osdl.org>
上级 615052dc
...@@ -639,7 +639,7 @@ struct sched_domain { ...@@ -639,7 +639,7 @@ struct sched_domain {
#endif #endif
}; };
extern void partition_sched_domains(cpumask_t *partition1, extern int partition_sched_domains(cpumask_t *partition1,
cpumask_t *partition2); cpumask_t *partition2);
/* /*
......
...@@ -5820,11 +5820,56 @@ static void init_numa_sched_groups_power(struct sched_group *group_head) ...@@ -5820,11 +5820,56 @@ static void init_numa_sched_groups_power(struct sched_group *group_head)
} }
#endif #endif
/* Free memory allocated for various sched_group structures */
static void free_sched_groups(const cpumask_t *cpu_map)
{
#ifdef CONFIG_NUMA
int i;
int cpu;
for_each_cpu_mask(cpu, *cpu_map) {
struct sched_group *sched_group_allnodes
= sched_group_allnodes_bycpu[cpu];
struct sched_group **sched_group_nodes
= sched_group_nodes_bycpu[cpu];
if (sched_group_allnodes) {
kfree(sched_group_allnodes);
sched_group_allnodes_bycpu[cpu] = NULL;
}
if (!sched_group_nodes)
continue;
for (i = 0; i < MAX_NUMNODES; i++) {
cpumask_t nodemask = node_to_cpumask(i);
struct sched_group *oldsg, *sg = sched_group_nodes[i];
cpus_and(nodemask, nodemask, *cpu_map);
if (cpus_empty(nodemask))
continue;
if (sg == NULL)
continue;
sg = sg->next;
next_sg:
oldsg = sg;
sg = sg->next;
kfree(oldsg);
if (oldsg != sched_group_nodes[i])
goto next_sg;
}
kfree(sched_group_nodes);
sched_group_nodes_bycpu[cpu] = NULL;
}
#endif
}
/* /*
* Build sched domains for a given set of cpus and attach the sched domains * Build sched domains for a given set of cpus and attach the sched domains
* to the individual cpus * to the individual cpus
*/ */
void build_sched_domains(const cpumask_t *cpu_map) static int build_sched_domains(const cpumask_t *cpu_map)
{ {
int i; int i;
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
...@@ -5834,11 +5879,11 @@ void build_sched_domains(const cpumask_t *cpu_map) ...@@ -5834,11 +5879,11 @@ void build_sched_domains(const cpumask_t *cpu_map)
/* /*
* Allocate the per-node list of sched groups * Allocate the per-node list of sched groups
*/ */
sched_group_nodes = kmalloc(sizeof(struct sched_group*)*MAX_NUMNODES, sched_group_nodes = kzalloc(sizeof(struct sched_group*)*MAX_NUMNODES,
GFP_ATOMIC); GFP_ATOMIC);
if (!sched_group_nodes) { if (!sched_group_nodes) {
printk(KERN_WARNING "Can not alloc sched group node list\n"); printk(KERN_WARNING "Can not alloc sched group node list\n");
return; return -ENOMEM;
} }
sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes; sched_group_nodes_bycpu[first_cpu(*cpu_map)] = sched_group_nodes;
#endif #endif
...@@ -5864,7 +5909,7 @@ void build_sched_domains(const cpumask_t *cpu_map) ...@@ -5864,7 +5909,7 @@ void build_sched_domains(const cpumask_t *cpu_map)
if (!sched_group_allnodes) { if (!sched_group_allnodes) {
printk(KERN_WARNING printk(KERN_WARNING
"Can not alloc allnodes sched group\n"); "Can not alloc allnodes sched group\n");
break; goto error;
} }
sched_group_allnodes_bycpu[i] sched_group_allnodes_bycpu[i]
= sched_group_allnodes; = sched_group_allnodes;
...@@ -5978,23 +6023,20 @@ void build_sched_domains(const cpumask_t *cpu_map) ...@@ -5978,23 +6023,20 @@ void build_sched_domains(const cpumask_t *cpu_map)
cpus_and(domainspan, domainspan, *cpu_map); cpus_and(domainspan, domainspan, *cpu_map);
sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL); sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
if (!sg) {
printk(KERN_WARNING "Can not alloc domain group for "
"node %d\n", i);
goto error;
}
sched_group_nodes[i] = sg; sched_group_nodes[i] = sg;
for_each_cpu_mask(j, nodemask) { for_each_cpu_mask(j, nodemask) {
struct sched_domain *sd; struct sched_domain *sd;
sd = &per_cpu(node_domains, j); sd = &per_cpu(node_domains, j);
sd->groups = sg; sd->groups = sg;
if (sd->groups == NULL) {
/* Turn off balancing if we have no groups */
sd->flags = 0;
}
}
if (!sg) {
printk(KERN_WARNING
"Can not alloc domain group for node %d\n", i);
continue;
} }
sg->cpu_power = 0; sg->cpu_power = 0;
sg->cpumask = nodemask; sg->cpumask = nodemask;
sg->next = sg;
cpus_or(covered, covered, nodemask); cpus_or(covered, covered, nodemask);
prev = sg; prev = sg;
...@@ -6017,15 +6059,15 @@ void build_sched_domains(const cpumask_t *cpu_map) ...@@ -6017,15 +6059,15 @@ void build_sched_domains(const cpumask_t *cpu_map)
if (!sg) { if (!sg) {
printk(KERN_WARNING printk(KERN_WARNING
"Can not alloc domain group for node %d\n", j); "Can not alloc domain group for node %d\n", j);
break; goto error;
} }
sg->cpu_power = 0; sg->cpu_power = 0;
sg->cpumask = tmp; sg->cpumask = tmp;
sg->next = prev->next;
cpus_or(covered, covered, tmp); cpus_or(covered, covered, tmp);
prev->next = sg; prev->next = sg;
prev = sg; prev = sg;
} }
prev->next = sched_group_nodes[i];
} }
#endif #endif
...@@ -6088,13 +6130,22 @@ void build_sched_domains(const cpumask_t *cpu_map) ...@@ -6088,13 +6130,22 @@ void build_sched_domains(const cpumask_t *cpu_map)
* Tune cache-hot values: * Tune cache-hot values:
*/ */
calibrate_migration_costs(cpu_map); calibrate_migration_costs(cpu_map);
return 0;
#ifdef CONFIG_NUMA
error:
free_sched_groups(cpu_map);
return -ENOMEM;
#endif
} }
/* /*
* Set up scheduler domains and groups. Callers must hold the hotplug lock. * Set up scheduler domains and groups. Callers must hold the hotplug lock.
*/ */
static void arch_init_sched_domains(const cpumask_t *cpu_map) static int arch_init_sched_domains(const cpumask_t *cpu_map)
{ {
cpumask_t cpu_default_map; cpumask_t cpu_default_map;
int err;
/* /*
* Setup mask for cpus without special case scheduling requirements. * Setup mask for cpus without special case scheduling requirements.
...@@ -6103,51 +6154,14 @@ static void arch_init_sched_domains(const cpumask_t *cpu_map) ...@@ -6103,51 +6154,14 @@ static void arch_init_sched_domains(const cpumask_t *cpu_map)
*/ */
cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map); cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
build_sched_domains(&cpu_default_map); err = build_sched_domains(&cpu_default_map);
return err;
} }
static void arch_destroy_sched_domains(const cpumask_t *cpu_map) static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
{ {
#ifdef CONFIG_NUMA free_sched_groups(cpu_map);
int i;
int cpu;
for_each_cpu_mask(cpu, *cpu_map) {
struct sched_group *sched_group_allnodes
= sched_group_allnodes_bycpu[cpu];
struct sched_group **sched_group_nodes
= sched_group_nodes_bycpu[cpu];
if (sched_group_allnodes) {
kfree(sched_group_allnodes);
sched_group_allnodes_bycpu[cpu] = NULL;
}
if (!sched_group_nodes)
continue;
for (i = 0; i < MAX_NUMNODES; i++) {
cpumask_t nodemask = node_to_cpumask(i);
struct sched_group *oldsg, *sg = sched_group_nodes[i];
cpus_and(nodemask, nodemask, *cpu_map);
if (cpus_empty(nodemask))
continue;
if (sg == NULL)
continue;
sg = sg->next;
next_sg:
oldsg = sg;
sg = sg->next;
kfree(oldsg);
if (oldsg != sched_group_nodes[i])
goto next_sg;
}
kfree(sched_group_nodes);
sched_group_nodes_bycpu[cpu] = NULL;
}
#endif
} }
/* /*
...@@ -6172,9 +6186,10 @@ static void detach_destroy_domains(const cpumask_t *cpu_map) ...@@ -6172,9 +6186,10 @@ static void detach_destroy_domains(const cpumask_t *cpu_map)
* correct sched domains * correct sched domains
* Call with hotplug lock held * Call with hotplug lock held
*/ */
void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2) int partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
{ {
cpumask_t change_map; cpumask_t change_map;
int err = 0;
cpus_and(*partition1, *partition1, cpu_online_map); cpus_and(*partition1, *partition1, cpu_online_map);
cpus_and(*partition2, *partition2, cpu_online_map); cpus_and(*partition2, *partition2, cpu_online_map);
...@@ -6183,9 +6198,11 @@ void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2) ...@@ -6183,9 +6198,11 @@ void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
/* Detach sched domains from all of the affected cpus */ /* Detach sched domains from all of the affected cpus */
detach_destroy_domains(&change_map); detach_destroy_domains(&change_map);
if (!cpus_empty(*partition1)) if (!cpus_empty(*partition1))
build_sched_domains(partition1); err = build_sched_domains(partition1);
if (!cpus_empty(*partition2)) if (!err && !cpus_empty(*partition2))
build_sched_domains(partition2); err = build_sched_domains(partition2);
return err;
} }
#ifdef CONFIG_HOTPLUG_CPU #ifdef CONFIG_HOTPLUG_CPU
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册