Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > fc11cd6e1c513a17304da94a5390f3cd > files > 2278

kernel-2.6.18-194.11.1.el5.src.rpm

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);