The iucv is the only user of the various functions that are used to bring parts of cpus up and down. Its the only allocpercpu user that will do I/O on per cpu objects (which is difficult to do with virtually mapped memory). And its the only use of allocpercpu where a GFP_DMA allocation is done. Remove the allocpercpu calls from iucv and code the allocation and freeing manually. Signed-off-by: Christoph Lameter --- net/iucv/iucv.c | 99 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 43 deletions(-) Index: linux-2.6/net/iucv/iucv.c =================================================================== --- linux-2.6.orig/net/iucv/iucv.c 2007-11-04 21:15:10.000000000 -0800 +++ linux-2.6/net/iucv/iucv.c 2007-11-04 21:22:50.000000000 -0800 @@ -97,7 +97,7 @@ struct iucv_irq_list { struct iucv_irq_data data; }; -static struct iucv_irq_data *iucv_irq_data; +static struct iucv_irq_data *iucv_irq_data[NR_CPUS]; static cpumask_t iucv_buffer_cpumask = CPU_MASK_NONE; static cpumask_t iucv_irq_cpumask = CPU_MASK_NONE; @@ -277,7 +277,7 @@ union iucv_param { /* * Anchor for per-cpu IUCV command parameter block. */ -static union iucv_param *iucv_param; +static union iucv_param *iucv_param[NR_CPUS]; /** * iucv_call_b2f0 @@ -356,7 +356,7 @@ static void iucv_allow_cpu(void *data) * 0x10 - Flag to allow priority message completion interrupts * 0x08 - Flag to allow IUCV control interrupts */ - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[cpu]; memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); @@ -377,7 +377,7 @@ static void iucv_block_cpu(void *data) union iucv_param *parm; /* Disable all iucv interrupts. */ - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[cpu]; memset(parm, 0, sizeof(union iucv_param)); iucv_call_b2f0(IUCV_SETMASK, parm); @@ -401,9 +401,9 @@ static void iucv_declare_cpu(void *data) return; /* Declare interrupt buffer. */ - parm = percpu_ptr(iucv_param, cpu); + parm = iucv_param[cpu]; memset(parm, 0, sizeof(union iucv_param)); - parm->db.ipbfadr1 = virt_to_phys(percpu_ptr(iucv_irq_data, cpu)); + parm->db.ipbfadr1 = virt_to_phys(iucv_irq_data[cpu]); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); if (rc) { char *err = "Unknown"; @@ -458,7 +458,7 @@ static void iucv_retrieve_cpu(void *data iucv_block_cpu(NULL); /* Retrieve interrupt buffer. */ - parm = percpu_ptr(iucv_param, cpu); + parm = iucv_param[cpu]; iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ @@ -558,13 +558,13 @@ static int __cpuinit iucv_cpu_notify(str switch (action) { case CPU_UP_PREPARE: case CPU_UP_PREPARE_FROZEN: - if (!percpu_populate(iucv_irq_data, - sizeof(struct iucv_irq_data), - GFP_KERNEL|GFP_DMA, cpu)) + iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_irq_data[cpu]) return NOTIFY_BAD; - if (!percpu_populate(iucv_param, sizeof(union iucv_param), - GFP_KERNEL|GFP_DMA, cpu)) { - percpu_depopulate(iucv_irq_data, cpu); + iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param[cpu]) return NOTIFY_BAD; } break; @@ -572,8 +572,10 @@ static int __cpuinit iucv_cpu_notify(str case CPU_UP_CANCELED_FROZEN: case CPU_DEAD: case CPU_DEAD_FROZEN: - percpu_depopulate(iucv_param, cpu); - percpu_depopulate(iucv_irq_data, cpu); + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; break; case CPU_ONLINE: case CPU_ONLINE_FROZEN: @@ -612,7 +614,7 @@ static int iucv_sever_pathid(u16 pathid, { union iucv_param *parm; - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -755,7 +757,7 @@ int iucv_path_accept(struct iucv_path *p local_bh_disable(); /* Prepare parameter block. */ - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ippathid = path->pathid; parm->ctrl.ipmsglim = path->msglim; @@ -799,7 +801,7 @@ int iucv_path_connect(struct iucv_path * BUG_ON(in_atomic()); spin_lock_bh(&iucv_table_lock); iucv_cleanup_queue(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->ctrl.ipmsglim = path->msglim; parm->ctrl.ipflags1 = path->flags; @@ -854,7 +856,7 @@ int iucv_path_quiesce(struct iucv_path * int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -881,7 +883,7 @@ int iucv_path_resume(struct iucv_path *p int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -936,7 +938,7 @@ int iucv_message_purge(struct iucv_path int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->purge.ippathid = path->pathid; parm->purge.ipmsgid = msg->id; @@ -1003,7 +1005,7 @@ int iucv_message_receive(struct iucv_pat } local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = (u32)(addr_t) buffer; parm->db.ipbfln1f = (u32) size; @@ -1040,7 +1042,7 @@ int iucv_message_reject(struct iucv_path int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); parm->db.ippathid = path->pathid; parm->db.ipmsgid = msg->id; @@ -1074,7 +1076,7 @@ int iucv_message_reply(struct iucv_path int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { parm->dpl.ippathid = path->pathid; @@ -1118,7 +1120,7 @@ int iucv_message_send(struct iucv_path * int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { /* Message of 8 bytes can be placed into the parameter list. */ @@ -1172,7 +1174,7 @@ int iucv_message_send2way(struct iucv_pa int rc; local_bh_disable(); - parm = percpu_ptr(iucv_param, smp_processor_id()); + parm = iucv_param[smp_processor_id()]; memset(parm, 0, sizeof(union iucv_param)); if (flags & IUCV_IPRMDATA) { parm->dpl.ippathid = path->pathid; @@ -1559,7 +1561,7 @@ static void iucv_external_interrupt(u16 struct iucv_irq_data *p; struct iucv_irq_list *work; - p = percpu_ptr(iucv_irq_data, smp_processor_id()); + p = iucv_irq_data[smp_processor_id()]; if (p->ippathid >= iucv_max_pathid) { printk(KERN_WARNING "iucv_do_int: Got interrupt with " "pathid %d > max_connections (%ld)\n", @@ -1598,6 +1600,7 @@ static void iucv_external_interrupt(u16 static int __init iucv_init(void) { int rc; + int cpu; if (!MACHINE_IS_VM) { rc = -EPROTONOSUPPORT; @@ -1617,19 +1620,21 @@ static int __init iucv_init(void) rc = PTR_ERR(iucv_root); goto out_bus; } - /* Note: GFP_DMA used to get memory below 2G */ - iucv_irq_data = percpu_alloc(sizeof(struct iucv_irq_data), - GFP_KERNEL|GFP_DMA); - if (!iucv_irq_data) { - rc = -ENOMEM; - goto out_root; - } - /* Allocate parameter blocks. */ - iucv_param = percpu_alloc(sizeof(union iucv_param), - GFP_KERNEL|GFP_DMA); - if (!iucv_param) { - rc = -ENOMEM; - goto out_extint; + + for_each_online_cpu(cpu) { + /* Note: GFP_DMA used to get memory below 2G */ + iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_irq_data[cpu]) { + rc = -ENOMEM; + goto out_root; + + /* Allocate parameter blocks. */ + iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu_to_node(cpu)); + if (!iucv_param[cpu]) { + rc = -ENOMEM; + goto out_extint; } register_hotcpu_notifier(&iucv_cpu_notifier); ASCEBC(iucv_error_no_listener, 16); @@ -1639,7 +1644,10 @@ static int __init iucv_init(void) return 0; out_extint: - percpu_free(iucv_irq_data); + for_each_cpu(cpu) { + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; + } out_root: s390_root_dev_unregister(iucv_root); out_bus: @@ -1658,6 +1666,7 @@ out: static void __exit iucv_exit(void) { struct iucv_irq_list *p, *n; + int cpu; spin_lock_irq(&iucv_queue_lock); list_for_each_entry_safe(p, n, &iucv_task_queue, list) @@ -1666,8 +1675,12 @@ static void __exit iucv_exit(void) kfree(p); spin_unlock_irq(&iucv_queue_lock); unregister_hotcpu_notifier(&iucv_cpu_notifier); - percpu_free(iucv_param); - percpu_free(iucv_irq_data); + for_each_cpu(cpu) { + kfree(iucv_param[cpu]); + iucv_param[cpu] = NULL; + kfree(iucv_irq_data[cpu]); + iucv_irq_data[cpu] = NULL; + } s390_root_dev_unregister(iucv_root); bus_unregister(&iucv_bus); unregister_external_interrupt(0x4000, iucv_external_interrupt); -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/