Some people have been commenting about slowness in starting up IUCV
connections to the TCPIP service on z/VM. Some mailing list messages
on this topic include:
http://www.marist.edu/htbin/wlvtype?LINUX-VM.25123
http://www.marist.edu/htbin/wlvtype?LINUX-VM.25137
It appears the issue with this is because of a race condition in the
drivers/s390/net/iucv.c code. The patch provided in this email should
remove the race condition.
The netiucv driver registers a handler with the iucv code. This handler
is supposed to recieve all packets that are sent with a specific pathid.
What ends up happening is that the connection established message is
received after the connection request is sent but before the handler is
registered. This patch solves this issue by turning off IUCV Control
Interrupts before issuing the connection request and reestablishes them
after registering the handler.
This patch can be applied to the latest 2.4 and 2.5 kernel series. I have
submitted this patch to [EMAIL PROTECTED]
If you have any questions or comments, please don't hesitate to contact me.
Thank you.
--
David Kennedy, Senior Linux Consultant, Linuxcare, Inc.
613.562.9594 tel, 613.562.9304 fax
[EMAIL PROTECTED], http://www.linuxcare.com/
Linuxcare. Putting open source to work.
diff -ur linux/drivers/s390/net/iucv.c new/iucv.c
--- linux/drivers/s390/net/iucv.c Fri Apr 12 12:38:32 2002
+++ new/iucv.c Fri Apr 12 12:37:19 2002
@@ -482,7 +482,7 @@
b2f0(__u32 code, void *parm)
{
iucv_debug("iparml before b2f0 call:");
- iucv_dumpit(parm, sizeof(iucv_param.param));
+ iucv_dumpit(parm, sizeof(iucv_param));
asm volatile (
"LRA 1,0(%1)\n\t"
@@ -494,7 +494,7 @@
);
iucv_debug("iparml after b2f0 call:");
- iucv_dumpit(parm, sizeof(iucv_param.param));
+ iucv_dumpit(parm, sizeof(iucv_param));
return (unsigned long)*((__u8 *)(parm + 3));
}
@@ -952,6 +952,24 @@
EBC_TOUPPER(parm->iptarget, sizeof(parm->iptarget));
}
+ /* In order to establish an IUCV connection, the procedure is:
+ *
+ * b2f0(CONNECT)
+ * take the ippathid from the b2f0 call
+ * register the handler to the ippathid
+ *
+ * Unfortunately, the ConnectionEstablished message gets sent after the
+ * b2f0(CONNECT) call but before the register is handled.
+ *
+ * In order for this race condition to be eliminated, the IUCV Control
+ * Interrupts must be disabled for the above procedure.
+ *
+ * David Kennedy <[EMAIL PROTECTED]>
+ */
+
+ /* Enable everything but IUCV Control messages */
+ iucv_setmask(~(IUCVControlInterruptsFlag));
+
parm->ipflags1 = (__u8)flags1;
b2f0_result = b2f0(CONNECT, parm);
@@ -963,6 +981,9 @@
add_pathid_result = iucv_add_pathid(parm->ippathid, h);
*pathid = parm->ippathid;
+ /* Enable everything again */
+ iucv_setmask(~0);
+
if (msglim)
*msglim = parm->ipmsglim;
if (flags1_out)
@@ -1961,6 +1982,7 @@
* 0x40 - Priority_MessagePendingInterruptsFlag
* 0x20 - Nonpriority_MessageCompletionInterruptsFlag
* 0x10 - Priority_MessageCompletionInterruptsFlag
+ * 0x08 - IUCVControlInterruptsFlag
* Output: NA
* Return: b2f0_result - return code from CP
*/
@@ -2129,7 +2151,7 @@
iucv_sever (int_buf->ippathid,
no_listener);
iucv_debug("add_pathid failed, rc = %d",
- (int)add_pathid_result);
+ (int)rc);
} else {
interrupt = h->interrupt_table;
if (interrupt->ConnectionPending) {
@@ -2146,11 +2168,15 @@
break;
case 0x02: /*connection complete */
+ iucv_debug("entering");
if (h) {
if (interrupt->ConnectionComplete)
+ {
+ iucv_debug("calling ConnectionComplete");
interrupt->ConnectionComplete(
(iucv_ConnectionComplete *)int_buf,
h->pgm_data);
+ }
else
iucv_debug("ConnectionComplete not called");
}
diff -ur linux/drivers/s390/net/iucv.h new/iucv.h
--- linux/drivers/s390/net/iucv.h Thu Apr 11 16:07:32 2002
+++ new/iucv.h Fri Apr 12 09:47:52 2002
@@ -62,6 +62,8 @@
#define Priority_MessagePendingInterruptsFlag 0x40
#define Nonpriority_MessageCompletionInterruptsFlag 0x20
#define Priority_MessageCompletionInterruptsFlag 0x10
+#define IUCVControlInterruptsFlag 0x08
+
/*
* Mapping of external interrupt buffers should be used with the corresponding
* interrupt types.
@@ -735,6 +737,7 @@
* 0x40 - Priority_MessagePendingInterruptsFlag
* 0x20 - Nonpriority_MessageCompletionInterruptsFlag
* 0x10 - Priority_MessageCompletionInterruptsFlag
+ * 0x08 - IUCVControlInterruptsFlag
* Output: NA
* Return: Return code from CP IUCV call.
*/
diff -ur linux/drivers/s390/net/netiucv.c new/netiucv.c
--- linux/drivers/s390/net/netiucv.c Fri Apr 12 12:38:41 2002
+++ new/netiucv.c Fri Apr 12 09:49:36 2002
@@ -443,6 +443,10 @@
iucv_connection *conn = (iucv_connection *)pgm_data;
iucv_event ev;
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s() called\n", __FUNCTION__);
+#endif
+
ev.conn = conn;
ev.data = (void *)eib;
fsm_event(conn->fsm, CONN_EVENT_CONN_ACK, &ev);
@@ -806,10 +810,15 @@
printk(KERN_DEBUG "%s('%s'): connecting ...\n",
conn->netdev->name, conn->userid);
#endif
+
+ /* We must set the state before calling iucv_connect because the callback
+ * handler could be called at any point after the connection request is
+ * sent. */
+
+ fsm_newstate(fi, CONN_STATE_SETUPWAIT);
rc = iucv_connect(&(conn->pathid), NETIUCV_QUEUELEN_DEFAULT, iucvMagic,
conn->userid, iucv_host, 0, NULL, NULL, conn->handle,
conn);
- fsm_newstate(fi, CONN_STATE_SETUPWAIT);
switch (rc) {
case 0:
return;