[SPARC64]: Fix memory leak when cpu hotplugging.
Every time a cpu is added via hotplug, we allocate the per-cpu MONDO queues but we never free them up. Freeing isn't easy since the first cpu gets this memory from bootmem. Therefore, the simplest thing to do to fix this bug is to allocate the queues for all possible cpus at boot time. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
6c70b6fc7b
commit
b434e71933
@ -115,11 +115,8 @@ hv_cpu_startup:
|
|||||||
call hard_smp_processor_id
|
call hard_smp_processor_id
|
||||||
nop
|
nop
|
||||||
|
|
||||||
mov %o0, %o1
|
call sun4v_register_mondo_queues
|
||||||
mov 0, %o0
|
nop
|
||||||
mov 0, %o2
|
|
||||||
call sun4v_init_mondo_queues
|
|
||||||
mov 1, %o3
|
|
||||||
|
|
||||||
call init_cur_cpu_trap
|
call init_cur_cpu_trap
|
||||||
mov %g6, %o0
|
mov %g6, %o0
|
||||||
|
@ -929,7 +929,7 @@ static void __cpuinit register_one_mondo(unsigned long paddr, unsigned long type
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
|
void __cpuinit sun4v_register_mondo_queues(int this_cpu)
|
||||||
{
|
{
|
||||||
struct trap_per_cpu *tb = &trap_block[this_cpu];
|
struct trap_per_cpu *tb = &trap_block[this_cpu];
|
||||||
|
|
||||||
@ -943,20 +943,10 @@ static void __cpuinit sun4v_register_mondo_queues(int this_cpu)
|
|||||||
tb->nonresum_qmask);
|
tb->nonresum_qmask);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
|
static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask)
|
||||||
{
|
{
|
||||||
unsigned long size = PAGE_ALIGN(qmask + 1);
|
unsigned long size = PAGE_ALIGN(qmask + 1);
|
||||||
unsigned long order = get_order(size);
|
void *p = __alloc_bootmem_low(size, size, 0);
|
||||||
void *p = NULL;
|
|
||||||
|
|
||||||
if (use_bootmem) {
|
|
||||||
p = __alloc_bootmem_low(size, size, 0);
|
|
||||||
} else {
|
|
||||||
struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
|
|
||||||
if (page)
|
|
||||||
p = page_address(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
|
prom_printf("SUN4V: Error, cannot allocate mondo queue.\n");
|
||||||
prom_halt();
|
prom_halt();
|
||||||
@ -965,19 +955,10 @@ static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask
|
|||||||
*pa_ptr = __pa(p);
|
*pa_ptr = __pa(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem)
|
static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask)
|
||||||
{
|
{
|
||||||
unsigned long size = PAGE_ALIGN(qmask + 1);
|
unsigned long size = PAGE_ALIGN(qmask + 1);
|
||||||
unsigned long order = get_order(size);
|
void *p = __alloc_bootmem_low(size, size, 0);
|
||||||
void *p = NULL;
|
|
||||||
|
|
||||||
if (use_bootmem) {
|
|
||||||
p = __alloc_bootmem_low(size, size, 0);
|
|
||||||
} else {
|
|
||||||
struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order);
|
|
||||||
if (page)
|
|
||||||
p = page_address(page);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p) {
|
if (!p) {
|
||||||
prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
|
prom_printf("SUN4V: Error, cannot allocate kbuf page.\n");
|
||||||
@ -987,18 +968,14 @@ static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask,
|
|||||||
*pa_ptr = __pa(p);
|
*pa_ptr = __pa(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem)
|
static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
void *page;
|
void *page;
|
||||||
|
|
||||||
BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
|
BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64));
|
||||||
|
|
||||||
if (use_bootmem)
|
page = alloc_bootmem_low_pages(PAGE_SIZE);
|
||||||
page = alloc_bootmem_low_pages(PAGE_SIZE);
|
|
||||||
else
|
|
||||||
page = (void *) get_zeroed_page(GFP_ATOMIC);
|
|
||||||
|
|
||||||
if (!page) {
|
if (!page) {
|
||||||
prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
|
prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n");
|
||||||
prom_halt();
|
prom_halt();
|
||||||
@ -1009,30 +986,27 @@ static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate and register the mondo and error queues for this cpu. */
|
/* Allocate mondo and error queues for all possible cpus. */
|
||||||
void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load)
|
static void __init sun4v_init_mondo_queues(void)
|
||||||
{
|
{
|
||||||
struct trap_per_cpu *tb = &trap_block[cpu];
|
int cpu;
|
||||||
|
|
||||||
if (alloc) {
|
for_each_possible_cpu(cpu) {
|
||||||
alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem);
|
struct trap_per_cpu *tb = &trap_block[cpu];
|
||||||
alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem);
|
|
||||||
alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem);
|
|
||||||
alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem);
|
|
||||||
alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem);
|
|
||||||
alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem);
|
|
||||||
|
|
||||||
init_cpu_send_mondo_info(tb, use_bootmem);
|
alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask);
|
||||||
|
alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask);
|
||||||
|
alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask);
|
||||||
|
alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask);
|
||||||
|
alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask);
|
||||||
|
alloc_one_kbuf(&tb->nonresum_kernel_buf_pa,
|
||||||
|
tb->nonresum_qmask);
|
||||||
|
|
||||||
|
init_cpu_send_mondo_info(tb);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (load) {
|
/* Load up the boot cpu's entries. */
|
||||||
if (cpu != hard_smp_processor_id()) {
|
sun4v_register_mondo_queues(hard_smp_processor_id());
|
||||||
prom_printf("SUN4V: init mondo on cpu %d not %d\n",
|
|
||||||
cpu, hard_smp_processor_id());
|
|
||||||
prom_halt();
|
|
||||||
}
|
|
||||||
sun4v_register_mondo_queues(cpu);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct irqaction timer_irq_action = {
|
static struct irqaction timer_irq_action = {
|
||||||
@ -1047,7 +1021,7 @@ void __init init_IRQ(void)
|
|||||||
memset(&ivector_table[0], 0, sizeof(ivector_table));
|
memset(&ivector_table[0], 0, sizeof(ivector_table));
|
||||||
|
|
||||||
if (tlb_type == hypervisor)
|
if (tlb_type == hypervisor)
|
||||||
sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1);
|
sun4v_init_mondo_queues();
|
||||||
|
|
||||||
/* We need to clear any IRQ's pending in the soft interrupt
|
/* We need to clear any IRQ's pending in the soft interrupt
|
||||||
* registers, a spurious one could be left around from the
|
* registers, a spurious one could be left around from the
|
||||||
|
@ -334,8 +334,6 @@ static void ldom_startcpu_cpuid(unsigned int cpu, unsigned long thread_reg)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load);
|
|
||||||
|
|
||||||
extern unsigned long sparc64_cpu_startup;
|
extern unsigned long sparc64_cpu_startup;
|
||||||
|
|
||||||
/* The OBP cpu startup callback truncates the 3rd arg cookie to
|
/* The OBP cpu startup callback truncates the 3rd arg cookie to
|
||||||
@ -359,9 +357,6 @@ static int __devinit smp_boot_one_cpu(unsigned int cpu)
|
|||||||
cpu_new_thread = task_thread_info(p);
|
cpu_new_thread = task_thread_info(p);
|
||||||
|
|
||||||
if (tlb_type == hypervisor) {
|
if (tlb_type == hypervisor) {
|
||||||
/* Alloc the mondo queues, cpu will load them. */
|
|
||||||
sun4v_init_mondo_queues(0, cpu, 1, 0);
|
|
||||||
|
|
||||||
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
|
#if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU)
|
||||||
if (ldom_domaining_enabled)
|
if (ldom_domaining_enabled)
|
||||||
ldom_startcpu_cpuid(cpu,
|
ldom_startcpu_cpuid(cpu,
|
||||||
|
@ -366,11 +366,8 @@ after_lock_tlb:
|
|||||||
call hard_smp_processor_id
|
call hard_smp_processor_id
|
||||||
nop
|
nop
|
||||||
|
|
||||||
mov %o0, %o1
|
call sun4v_register_mondo_queues
|
||||||
mov 0, %o0
|
nop
|
||||||
mov 0, %o2
|
|
||||||
call sun4v_init_mondo_queues
|
|
||||||
mov 1, %o3
|
|
||||||
|
|
||||||
1: call init_cur_cpu_trap
|
1: call init_cur_cpu_trap
|
||||||
ldx [%l0], %o0
|
ldx [%l0], %o0
|
||||||
|
Loading…
Reference in New Issue
Block a user