From: Hans-Joachim Picht <hpicht@redhat.com> Date: Thu, 25 Jun 2009 18:17:09 +0200 Subject: [net] iucv: provide second per-cpu cmd parameter block Message-id: 20090625161709.GA12530@redhat.com O-Subject: [RHEL5 U4 PATCH 1/1] iucv - provide second per-cpu IUCV command parameter block Bugzilla: 503240 RH-Acked-by: David Miller <davem@redhat.com> RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> Description ============ Some of the IUCV commands can be invoked in interrupt context. Those commands need a different per-cpu IUCV command parameter block, otherwise they might overwrite an IUCV command parameter of a not yet finished IUCV command invocation in process context. This fix is essential for IBM Systems Director which makes use of iucv. Bugzilla ========= BZ 503240 https://bugzilla.redhat.com/show_bug.cgi?id=503240 Upstream status of the patch: ============================= The patch has been posted upstream. http://kerneltrap.org/mailarchive/linux-netdev/2009/4/21/5530964 Test status: ============ The patch has been tested and fixes the problem. The fix has been verified by the IBM test department. Please ACK. With best regards, --Hans diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index a0d4949..569c6e4 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c @@ -278,6 +278,7 @@ union iucv_param { * Anchor for per-cpu IUCV command parameter block. */ static union iucv_param *iucv_param; +static union iucv_param *iucv_param_irq; /** * iucv_call_b2f0 @@ -356,7 +357,7 @@ static void iucv_allow_cpu(void *data) * 0x10 - Flag to allow priority message completion interrupts * 0x08 - Flag to allow IUCV control interrupts */ - parm = per_cpu_ptr(iucv_param, smp_processor_id()); + parm = per_cpu_ptr(iucv_param_irq, smp_processor_id()); memset(parm, 0, sizeof(union iucv_param)); parm->set_mask.ipmask = 0xf8; iucv_call_b2f0(IUCV_SETMASK, parm); @@ -377,7 +378,7 @@ static void iucv_block_cpu(void *data) union iucv_param *parm; /* Disable all iucv interrupts. */ - parm = per_cpu_ptr(iucv_param, smp_processor_id()); + parm = per_cpu_ptr(iucv_param_irq, smp_processor_id()); memset(parm, 0, sizeof(union iucv_param)); iucv_call_b2f0(IUCV_SETMASK, parm); @@ -401,7 +402,7 @@ static void iucv_declare_cpu(void *data) return; /* Declare interrupt buffer. */ - parm = per_cpu_ptr(iucv_param, cpu); + parm = per_cpu_ptr(iucv_param_irq, cpu); memset(parm, 0, sizeof(union iucv_param)); parm->db.ipbfadr1 = virt_to_phys(per_cpu_ptr(iucv_irq_data, cpu)); rc = iucv_call_b2f0(IUCV_DECLARE_BUFFER, parm); @@ -458,7 +459,7 @@ static void iucv_retrieve_cpu(void *data) iucv_block_cpu(NULL); /* Retrieve interrupt buffer. */ - parm = per_cpu_ptr(iucv_param, cpu); + parm = per_cpu_ptr(iucv_param_irq, cpu); iucv_call_b2f0(IUCV_RETRIEVE_BUFFER, parm); /* Clear indication that an iucv buffer exists for this cpu. */ @@ -682,9 +683,16 @@ static int __cpuinit iucv_cpu_notify(struct notifier_block *self, iucv_percpu_depopulate(iucv_irq_data, cpu); return NOTIFY_BAD; } + if (!iucv_percpu_populate(iucv_param_irq, sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, cpu)) { + iucv_percpu_depopulate(iucv_param, cpu); + iucv_percpu_depopulate(iucv_irq_data, cpu); + return NOTIFY_BAD; + } break; case CPU_UP_CANCELED: case CPU_DEAD: + iucv_percpu_depopulate(iucv_param_irq, cpu); iucv_percpu_depopulate(iucv_param, cpu); iucv_percpu_depopulate(iucv_irq_data, cpu); break; @@ -747,7 +755,7 @@ static int iucv_sever_pathid(u16 pathid, u8 userdata[16]) { union iucv_param *parm; - parm = per_cpu_ptr(iucv_param, smp_processor_id()); + parm = per_cpu_ptr(iucv_param_irq, smp_processor_id()); memset(parm, 0, sizeof(union iucv_param)); if (userdata) memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); @@ -1849,6 +1857,13 @@ static int __init iucv_init(void) rc = -ENOMEM; goto out_extint; } + iucv_param_irq = __iucv_percpu_alloc_mask(sizeof(union iucv_param), + GFP_KERNEL|GFP_DMA, + &cpu_online_map); + if (!iucv_param_irq) { + rc = -ENOMEM; + goto out_parm; + } #ifdef CONFIG_SMP register_cpu_notifier(&iucv_cpu_notifier); #endif @@ -1858,6 +1873,8 @@ static int __init iucv_init(void) iucv_available = 1; return 0; +out_parm: + iucv_percpu_free(iucv_param); out_extint: iucv_percpu_free(iucv_irq_data); out_root: @@ -1888,6 +1905,7 @@ static void __exit iucv_exit(void) #ifdef CONFIG_SMP unregister_cpu_notifier(&iucv_cpu_notifier); #endif + iucv_percpu_free(iucv_param_irq); iucv_percpu_free(iucv_param); iucv_percpu_free(iucv_irq_data); s390_root_dev_unregister(iucv_root);