Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+28 -65
+2 -5
arch/sparc64/kernel/hvtramp.S
··· 115 115 call hard_smp_processor_id 116 116 nop 117 117 118 - mov %o0, %o1 119 - mov 0, %o0 120 - mov 0, %o2 121 - call sun4v_init_mondo_queues 122 - mov 1, %o3 118 + call sun4v_register_mondo_queues 119 + nop 123 120 124 121 call init_cur_cpu_trap 125 122 mov %g6, %o0
+24 -50
arch/sparc64/kernel/irq.c
··· 929 929 } 930 930 } 931 931 932 - static void __cpuinit sun4v_register_mondo_queues(int this_cpu) 932 + void __cpuinit sun4v_register_mondo_queues(int this_cpu) 933 933 { 934 934 struct trap_per_cpu *tb = &trap_block[this_cpu]; 935 935 ··· 943 943 tb->nonresum_qmask); 944 944 } 945 945 946 - static void __cpuinit alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) 946 + static void __init alloc_one_mondo(unsigned long *pa_ptr, unsigned long qmask) 947 947 { 948 948 unsigned long size = PAGE_ALIGN(qmask + 1); 949 - unsigned long order = get_order(size); 950 - void *p = NULL; 951 - 952 - if (use_bootmem) { 953 - p = __alloc_bootmem_low(size, size, 0); 954 - } else { 955 - struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); 956 - if (page) 957 - p = page_address(page); 958 - } 959 - 949 + void *p = __alloc_bootmem_low(size, size, 0); 960 950 if (!p) { 961 951 prom_printf("SUN4V: Error, cannot allocate mondo queue.\n"); 962 952 prom_halt(); ··· 955 965 *pa_ptr = __pa(p); 956 966 } 957 967 958 - static void __cpuinit alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask, int use_bootmem) 968 + static void __init alloc_one_kbuf(unsigned long *pa_ptr, unsigned long qmask) 959 969 { 960 970 unsigned long size = PAGE_ALIGN(qmask + 1); 961 - unsigned long order = get_order(size); 962 - void *p = NULL; 963 - 964 - if (use_bootmem) { 965 - p = __alloc_bootmem_low(size, size, 0); 966 - } else { 967 - struct page *page = alloc_pages(GFP_ATOMIC | __GFP_ZERO, order); 968 - if (page) 969 - p = page_address(page); 970 - } 971 + void *p = __alloc_bootmem_low(size, size, 0); 971 972 972 973 if (!p) { 973 974 prom_printf("SUN4V: Error, cannot allocate kbuf page.\n"); ··· 968 987 *pa_ptr = __pa(p); 969 988 } 970 989 971 - static void __cpuinit init_cpu_send_mondo_info(struct trap_per_cpu *tb, int use_bootmem) 990 + static void __init init_cpu_send_mondo_info(struct trap_per_cpu *tb) 972 991 { 973 992 #ifdef CONFIG_SMP 974 993 void *page; 975 994 976 995 BUILD_BUG_ON((NR_CPUS * sizeof(u16)) > (PAGE_SIZE - 64)); 977 996 978 - if (use_bootmem) 979 - page = alloc_bootmem_low_pages(PAGE_SIZE); 980 - else 981 - page = (void *) get_zeroed_page(GFP_ATOMIC); 982 - 997 + page = alloc_bootmem_low_pages(PAGE_SIZE); 983 998 if (!page) { 984 999 prom_printf("SUN4V: Error, cannot allocate cpu mondo page.\n"); 985 1000 prom_halt(); ··· 986 1009 #endif 987 1010 } 988 1011 989 - /* Allocate and register the mondo and error queues for this cpu. */ 990 - void __cpuinit sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load) 1012 + /* Allocate mondo and error queues for all possible cpus. */ 1013 + static void __init sun4v_init_mondo_queues(void) 991 1014 { 992 - struct trap_per_cpu *tb = &trap_block[cpu]; 1015 + int cpu; 993 1016 994 - if (alloc) { 995 - alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask, use_bootmem); 996 - alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask, use_bootmem); 997 - alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask, use_bootmem); 998 - alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask, use_bootmem); 999 - alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask, use_bootmem); 1000 - alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, tb->nonresum_qmask, use_bootmem); 1017 + for_each_possible_cpu(cpu) { 1018 + struct trap_per_cpu *tb = &trap_block[cpu]; 1001 1019 1002 - init_cpu_send_mondo_info(tb, use_bootmem); 1020 + alloc_one_mondo(&tb->cpu_mondo_pa, tb->cpu_mondo_qmask); 1021 + alloc_one_mondo(&tb->dev_mondo_pa, tb->dev_mondo_qmask); 1022 + alloc_one_mondo(&tb->resum_mondo_pa, tb->resum_qmask); 1023 + alloc_one_kbuf(&tb->resum_kernel_buf_pa, tb->resum_qmask); 1024 + alloc_one_mondo(&tb->nonresum_mondo_pa, tb->nonresum_qmask); 1025 + alloc_one_kbuf(&tb->nonresum_kernel_buf_pa, 1026 + tb->nonresum_qmask); 1027 + 1028 + init_cpu_send_mondo_info(tb); 1003 1029 } 1004 1030 1005 - if (load) { 1006 - if (cpu != hard_smp_processor_id()) { 1007 - prom_printf("SUN4V: init mondo on cpu %d not %d\n", 1008 - cpu, hard_smp_processor_id()); 1009 - prom_halt(); 1010 - } 1011 - sun4v_register_mondo_queues(cpu); 1012 - } 1031 + /* Load up the boot cpu's entries. */ 1032 + sun4v_register_mondo_queues(hard_smp_processor_id()); 1013 1033 } 1014 1034 1015 1035 static struct irqaction timer_irq_action = { ··· 1021 1047 memset(&ivector_table[0], 0, sizeof(ivector_table)); 1022 1048 1023 1049 if (tlb_type == hypervisor) 1024 - sun4v_init_mondo_queues(1, hard_smp_processor_id(), 1, 1); 1050 + sun4v_init_mondo_queues(); 1025 1051 1026 1052 /* We need to clear any IRQ's pending in the soft interrupt 1027 1053 * registers, a spurious one could be left around from the
-5
arch/sparc64/kernel/smp.c
··· 334 334 } 335 335 #endif 336 336 337 - extern void sun4v_init_mondo_queues(int use_bootmem, int cpu, int alloc, int load); 338 - 339 337 extern unsigned long sparc64_cpu_startup; 340 338 341 339 /* The OBP cpu startup callback truncates the 3rd arg cookie to ··· 357 359 cpu_new_thread = task_thread_info(p); 358 360 359 361 if (tlb_type == hypervisor) { 360 - /* Alloc the mondo queues, cpu will load them. */ 361 - sun4v_init_mondo_queues(0, cpu, 1, 0); 362 - 363 362 #if defined(CONFIG_SUN_LDOMS) && defined(CONFIG_HOTPLUG_CPU) 364 363 if (ldom_domaining_enabled) 365 364 ldom_startcpu_cpuid(cpu,
+2 -5
arch/sparc64/kernel/trampoline.S
··· 366 366 call hard_smp_processor_id 367 367 nop 368 368 369 - mov %o0, %o1 370 - mov 0, %o0 371 - mov 0, %o2 372 - call sun4v_init_mondo_queues 373 - mov 1, %o3 369 + call sun4v_register_mondo_queues 370 + nop 374 371 375 372 1: call init_cur_cpu_trap 376 373 ldx [%l0], %o0