Commit 6c005961 authored by Ursula Braun's avatar Ursula Braun Committed by Martin Schwidefsky

[S390] iucv: establish reboot notifier

To guarantee a proper cleanup, patch adds a reboot notifier to
the iucv base code, which disables iucv interrupts, shuts down
established iucv pathes, and removes iucv declarations for z/VM.

Checks have to be added to the iucv-API functions, whether
iucv-buffers removed at reboot time are still declared.
Signed-off-by: default avatarUrsula Braun <ursula.braun@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 62b74942
/* /*
* IUCV base infrastructure. * IUCV base infrastructure.
* *
* Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation * Copyright IBM Corp. 2001, 2009
*
* Author(s): * Author(s):
* Original source: * Original source:
* Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
...@@ -45,6 +46,7 @@ ...@@ -45,6 +46,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/cpu.h> #include <linux/cpu.h>
#include <linux/reboot.h>
#include <net/iucv/iucv.h> #include <net/iucv/iucv.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
...@@ -758,6 +760,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp) ...@@ -758,6 +760,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp)
} }
EXPORT_SYMBOL(iucv_unregister); EXPORT_SYMBOL(iucv_unregister);
static int iucv_reboot_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
int i, rc;
get_online_cpus();
on_each_cpu(iucv_block_cpu, NULL, 1);
preempt_disable();
for (i = 0; i < iucv_max_pathid; i++) {
if (iucv_path_table[i])
rc = iucv_sever_pathid(i, NULL);
}
preempt_enable();
put_online_cpus();
iucv_disable();
return NOTIFY_DONE;
}
static struct notifier_block iucv_reboot_notifier = {
.notifier_call = iucv_reboot_event,
};
/** /**
* iucv_path_accept * iucv_path_accept
* @path: address of iucv path structure * @path: address of iucv path structure
...@@ -777,6 +801,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, ...@@ -777,6 +801,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
/* Prepare parameter block. */ /* Prepare parameter block. */
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
...@@ -792,6 +820,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, ...@@ -792,6 +820,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler,
path->msglim = parm->ctrl.ipmsglim; path->msglim = parm->ctrl.ipmsglim;
path->flags = parm->ctrl.ipflags1; path->flags = parm->ctrl.ipflags1;
} }
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -821,6 +850,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, ...@@ -821,6 +850,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
spin_lock_bh(&iucv_table_lock); spin_lock_bh(&iucv_table_lock);
iucv_cleanup_queue(); iucv_cleanup_queue();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->ctrl.ipmsglim = path->msglim; parm->ctrl.ipmsglim = path->msglim;
...@@ -855,6 +888,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, ...@@ -855,6 +888,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler,
rc = -EIO; rc = -EIO;
} }
} }
out:
spin_unlock_bh(&iucv_table_lock); spin_unlock_bh(&iucv_table_lock);
return rc; return rc;
} }
...@@ -876,12 +910,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) ...@@ -876,12 +910,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16])
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (userdata) if (userdata)
memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
parm->ctrl.ippathid = path->pathid; parm->ctrl.ippathid = path->pathid;
rc = iucv_call_b2f0(IUCV_QUIESCE, parm); rc = iucv_call_b2f0(IUCV_QUIESCE, parm);
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -903,12 +942,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) ...@@ -903,12 +942,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16])
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (userdata) if (userdata)
memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser));
parm->ctrl.ippathid = path->pathid; parm->ctrl.ippathid = path->pathid;
rc = iucv_call_b2f0(IUCV_RESUME, parm); rc = iucv_call_b2f0(IUCV_RESUME, parm);
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -927,6 +971,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) ...@@ -927,6 +971,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
int rc; int rc;
preempt_disable(); preempt_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
if (iucv_active_cpu != smp_processor_id()) if (iucv_active_cpu != smp_processor_id())
spin_lock_bh(&iucv_table_lock); spin_lock_bh(&iucv_table_lock);
rc = iucv_sever_pathid(path->pathid, userdata); rc = iucv_sever_pathid(path->pathid, userdata);
...@@ -934,6 +982,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) ...@@ -934,6 +982,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16])
list_del_init(&path->list); list_del_init(&path->list);
if (iucv_active_cpu != smp_processor_id()) if (iucv_active_cpu != smp_processor_id())
spin_unlock_bh(&iucv_table_lock); spin_unlock_bh(&iucv_table_lock);
out:
preempt_enable(); preempt_enable();
return rc; return rc;
} }
...@@ -956,6 +1005,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, ...@@ -956,6 +1005,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->purge.ippathid = path->pathid; parm->purge.ippathid = path->pathid;
...@@ -967,6 +1020,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, ...@@ -967,6 +1020,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8;
msg->tag = parm->purge.ipmsgtag; msg->tag = parm->purge.ipmsgtag;
} }
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -1043,6 +1097,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, ...@@ -1043,6 +1097,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
if (msg->flags & IUCV_IPRMDATA) if (msg->flags & IUCV_IPRMDATA)
return iucv_message_receive_iprmdata(path, msg, flags, return iucv_message_receive_iprmdata(path, msg, flags,
buffer, size, residual); buffer, size, residual);
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->db.ipbfadr1 = (u32)(addr_t) buffer; parm->db.ipbfadr1 = (u32)(addr_t) buffer;
...@@ -1058,6 +1116,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, ...@@ -1058,6 +1116,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
if (residual) if (residual)
*residual = parm->db.ipbfln1f; *residual = parm->db.ipbfln1f;
} }
out:
return rc; return rc;
} }
EXPORT_SYMBOL(__iucv_message_receive); EXPORT_SYMBOL(__iucv_message_receive);
...@@ -1111,6 +1170,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) ...@@ -1111,6 +1170,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
parm->db.ippathid = path->pathid; parm->db.ippathid = path->pathid;
...@@ -1118,6 +1181,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) ...@@ -1118,6 +1181,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg)
parm->db.iptrgcls = msg->class; parm->db.iptrgcls = msg->class;
parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID);
rc = iucv_call_b2f0(IUCV_REJECT, parm); rc = iucv_call_b2f0(IUCV_REJECT, parm);
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -1145,6 +1209,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, ...@@ -1145,6 +1209,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
...@@ -1162,6 +1230,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, ...@@ -1162,6 +1230,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
parm->db.iptrgcls = msg->class; parm->db.iptrgcls = msg->class;
} }
rc = iucv_call_b2f0(IUCV_REPLY, parm); rc = iucv_call_b2f0(IUCV_REPLY, parm);
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -1190,6 +1259,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, ...@@ -1190,6 +1259,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
union iucv_param *parm; union iucv_param *parm;
int rc; int rc;
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
...@@ -1212,6 +1285,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, ...@@ -1212,6 +1285,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
rc = iucv_call_b2f0(IUCV_SEND, parm); rc = iucv_call_b2f0(IUCV_SEND, parm);
if (!rc) if (!rc)
msg->id = parm->db.ipmsgid; msg->id = parm->db.ipmsgid;
out:
return rc; return rc;
} }
EXPORT_SYMBOL(__iucv_message_send); EXPORT_SYMBOL(__iucv_message_send);
...@@ -1272,6 +1346,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, ...@@ -1272,6 +1346,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
int rc; int rc;
local_bh_disable(); local_bh_disable();
if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) {
rc = -EIO;
goto out;
}
parm = iucv_param[smp_processor_id()]; parm = iucv_param[smp_processor_id()];
memset(parm, 0, sizeof(union iucv_param)); memset(parm, 0, sizeof(union iucv_param));
if (flags & IUCV_IPRMDATA) { if (flags & IUCV_IPRMDATA) {
...@@ -1297,6 +1375,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, ...@@ -1297,6 +1375,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg,
rc = iucv_call_b2f0(IUCV_SEND, parm); rc = iucv_call_b2f0(IUCV_SEND, parm);
if (!rc) if (!rc)
msg->id = parm->db.ipmsgid; msg->id = parm->db.ipmsgid;
out:
local_bh_enable(); local_bh_enable();
return rc; return rc;
} }
...@@ -1740,15 +1819,20 @@ static int __init iucv_init(void) ...@@ -1740,15 +1819,20 @@ static int __init iucv_init(void)
rc = register_hotcpu_notifier(&iucv_cpu_notifier); rc = register_hotcpu_notifier(&iucv_cpu_notifier);
if (rc) if (rc)
goto out_free; goto out_free;
rc = register_reboot_notifier(&iucv_reboot_notifier);
if (rc)
goto out_cpu;
ASCEBC(iucv_error_no_listener, 16); ASCEBC(iucv_error_no_listener, 16);
ASCEBC(iucv_error_no_memory, 16); ASCEBC(iucv_error_no_memory, 16);
ASCEBC(iucv_error_pathid, 16); ASCEBC(iucv_error_pathid, 16);
iucv_available = 1; iucv_available = 1;
rc = bus_register(&iucv_bus); rc = bus_register(&iucv_bus);
if (rc) if (rc)
goto out_cpu; goto out_reboot;
return 0; return 0;
out_reboot:
unregister_reboot_notifier(&iucv_reboot_notifier);
out_cpu: out_cpu:
unregister_hotcpu_notifier(&iucv_cpu_notifier); unregister_hotcpu_notifier(&iucv_cpu_notifier);
out_free: out_free:
...@@ -1783,6 +1867,7 @@ static void __exit iucv_exit(void) ...@@ -1783,6 +1867,7 @@ static void __exit iucv_exit(void)
list_for_each_entry_safe(p, n, &iucv_work_queue, list) list_for_each_entry_safe(p, n, &iucv_work_queue, list)
kfree(p); kfree(p);
spin_unlock_irq(&iucv_queue_lock); spin_unlock_irq(&iucv_queue_lock);
unregister_reboot_notifier(&iucv_reboot_notifier);
unregister_hotcpu_notifier(&iucv_cpu_notifier); unregister_hotcpu_notifier(&iucv_cpu_notifier);
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
kfree(iucv_param_irq[cpu]); kfree(iucv_param_irq[cpu]);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment