diff options
author | Ursula Braun <ursula.braun@de.ibm.com> | 2009-06-16 04:30:41 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2009-06-16 04:31:17 -0400 |
commit | 6c005961c15ff85fe1047c197d50b843567c89f8 (patch) | |
tree | 4021c62c2a4469ccfd82dd9bfe185a3258a4b60f | |
parent | 62b7494209495847269a6ce0504cbefd23d42eb1 (diff) |
[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: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | net/iucv/iucv.c | 89 |
1 files changed, 87 insertions, 2 deletions
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index 61e8038a55ee..0e9f212dd928 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
@@ -1,7 +1,8 @@ | |||
1 | /* | 1 | /* |
2 | * IUCV base infrastructure. | 2 | * IUCV base infrastructure. |
3 | * | 3 | * |
4 | * Copyright 2001, 2006 IBM Deutschland Entwicklung GmbH, IBM Corporation | 4 | * Copyright IBM Corp. 2001, 2009 |
5 | * | ||
5 | * Author(s): | 6 | * Author(s): |
6 | * Original source: | 7 | * Original source: |
7 | * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 | 8 | * Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000 |
@@ -45,6 +46,7 @@ | |||
45 | #include <linux/err.h> | 46 | #include <linux/err.h> |
46 | #include <linux/device.h> | 47 | #include <linux/device.h> |
47 | #include <linux/cpu.h> | 48 | #include <linux/cpu.h> |
49 | #include <linux/reboot.h> | ||
48 | #include <net/iucv/iucv.h> | 50 | #include <net/iucv/iucv.h> |
49 | #include <asm/atomic.h> | 51 | #include <asm/atomic.h> |
50 | #include <asm/ebcdic.h> | 52 | #include <asm/ebcdic.h> |
@@ -758,6 +760,28 @@ void iucv_unregister(struct iucv_handler *handler, int smp) | |||
758 | } | 760 | } |
759 | EXPORT_SYMBOL(iucv_unregister); | 761 | EXPORT_SYMBOL(iucv_unregister); |
760 | 762 | ||
763 | static int iucv_reboot_event(struct notifier_block *this, | ||
764 | unsigned long event, void *ptr) | ||
765 | { | ||
766 | int i, rc; | ||
767 | |||
768 | get_online_cpus(); | ||
769 | on_each_cpu(iucv_block_cpu, NULL, 1); | ||
770 | preempt_disable(); | ||
771 | for (i = 0; i < iucv_max_pathid; i++) { | ||
772 | if (iucv_path_table[i]) | ||
773 | rc = iucv_sever_pathid(i, NULL); | ||
774 | } | ||
775 | preempt_enable(); | ||
776 | put_online_cpus(); | ||
777 | iucv_disable(); | ||
778 | return NOTIFY_DONE; | ||
779 | } | ||
780 | |||
781 | static struct notifier_block iucv_reboot_notifier = { | ||
782 | .notifier_call = iucv_reboot_event, | ||
783 | }; | ||
784 | |||
761 | /** | 785 | /** |
762 | * iucv_path_accept | 786 | * iucv_path_accept |
763 | * @path: address of iucv path structure | 787 | * @path: address of iucv path structure |
@@ -777,6 +801,10 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, | |||
777 | int rc; | 801 | int rc; |
778 | 802 | ||
779 | local_bh_disable(); | 803 | local_bh_disable(); |
804 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
805 | rc = -EIO; | ||
806 | goto out; | ||
807 | } | ||
780 | /* Prepare parameter block. */ | 808 | /* Prepare parameter block. */ |
781 | parm = iucv_param[smp_processor_id()]; | 809 | parm = iucv_param[smp_processor_id()]; |
782 | memset(parm, 0, sizeof(union iucv_param)); | 810 | memset(parm, 0, sizeof(union iucv_param)); |
@@ -792,6 +820,7 @@ int iucv_path_accept(struct iucv_path *path, struct iucv_handler *handler, | |||
792 | path->msglim = parm->ctrl.ipmsglim; | 820 | path->msglim = parm->ctrl.ipmsglim; |
793 | path->flags = parm->ctrl.ipflags1; | 821 | path->flags = parm->ctrl.ipflags1; |
794 | } | 822 | } |
823 | out: | ||
795 | local_bh_enable(); | 824 | local_bh_enable(); |
796 | return rc; | 825 | return rc; |
797 | } | 826 | } |
@@ -821,6 +850,10 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, | |||
821 | 850 | ||
822 | spin_lock_bh(&iucv_table_lock); | 851 | spin_lock_bh(&iucv_table_lock); |
823 | iucv_cleanup_queue(); | 852 | iucv_cleanup_queue(); |
853 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
854 | rc = -EIO; | ||
855 | goto out; | ||
856 | } | ||
824 | parm = iucv_param[smp_processor_id()]; | 857 | parm = iucv_param[smp_processor_id()]; |
825 | memset(parm, 0, sizeof(union iucv_param)); | 858 | memset(parm, 0, sizeof(union iucv_param)); |
826 | parm->ctrl.ipmsglim = path->msglim; | 859 | parm->ctrl.ipmsglim = path->msglim; |
@@ -855,6 +888,7 @@ int iucv_path_connect(struct iucv_path *path, struct iucv_handler *handler, | |||
855 | rc = -EIO; | 888 | rc = -EIO; |
856 | } | 889 | } |
857 | } | 890 | } |
891 | out: | ||
858 | spin_unlock_bh(&iucv_table_lock); | 892 | spin_unlock_bh(&iucv_table_lock); |
859 | return rc; | 893 | return rc; |
860 | } | 894 | } |
@@ -876,12 +910,17 @@ int iucv_path_quiesce(struct iucv_path *path, u8 userdata[16]) | |||
876 | int rc; | 910 | int rc; |
877 | 911 | ||
878 | local_bh_disable(); | 912 | local_bh_disable(); |
913 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
914 | rc = -EIO; | ||
915 | goto out; | ||
916 | } | ||
879 | parm = iucv_param[smp_processor_id()]; | 917 | parm = iucv_param[smp_processor_id()]; |
880 | memset(parm, 0, sizeof(union iucv_param)); | 918 | memset(parm, 0, sizeof(union iucv_param)); |
881 | if (userdata) | 919 | if (userdata) |
882 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 920 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
883 | parm->ctrl.ippathid = path->pathid; | 921 | parm->ctrl.ippathid = path->pathid; |
884 | rc = iucv_call_b2f0(IUCV_QUIESCE, parm); | 922 | rc = iucv_call_b2f0(IUCV_QUIESCE, parm); |
923 | out: | ||
885 | local_bh_enable(); | 924 | local_bh_enable(); |
886 | return rc; | 925 | return rc; |
887 | } | 926 | } |
@@ -903,12 +942,17 @@ int iucv_path_resume(struct iucv_path *path, u8 userdata[16]) | |||
903 | int rc; | 942 | int rc; |
904 | 943 | ||
905 | local_bh_disable(); | 944 | local_bh_disable(); |
945 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
946 | rc = -EIO; | ||
947 | goto out; | ||
948 | } | ||
906 | parm = iucv_param[smp_processor_id()]; | 949 | parm = iucv_param[smp_processor_id()]; |
907 | memset(parm, 0, sizeof(union iucv_param)); | 950 | memset(parm, 0, sizeof(union iucv_param)); |
908 | if (userdata) | 951 | if (userdata) |
909 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); | 952 | memcpy(parm->ctrl.ipuser, userdata, sizeof(parm->ctrl.ipuser)); |
910 | parm->ctrl.ippathid = path->pathid; | 953 | parm->ctrl.ippathid = path->pathid; |
911 | rc = iucv_call_b2f0(IUCV_RESUME, parm); | 954 | rc = iucv_call_b2f0(IUCV_RESUME, parm); |
955 | out: | ||
912 | local_bh_enable(); | 956 | local_bh_enable(); |
913 | return rc; | 957 | return rc; |
914 | } | 958 | } |
@@ -927,6 +971,10 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) | |||
927 | int rc; | 971 | int rc; |
928 | 972 | ||
929 | preempt_disable(); | 973 | preempt_disable(); |
974 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
975 | rc = -EIO; | ||
976 | goto out; | ||
977 | } | ||
930 | if (iucv_active_cpu != smp_processor_id()) | 978 | if (iucv_active_cpu != smp_processor_id()) |
931 | spin_lock_bh(&iucv_table_lock); | 979 | spin_lock_bh(&iucv_table_lock); |
932 | rc = iucv_sever_pathid(path->pathid, userdata); | 980 | rc = iucv_sever_pathid(path->pathid, userdata); |
@@ -934,6 +982,7 @@ int iucv_path_sever(struct iucv_path *path, u8 userdata[16]) | |||
934 | list_del_init(&path->list); | 982 | list_del_init(&path->list); |
935 | if (iucv_active_cpu != smp_processor_id()) | 983 | if (iucv_active_cpu != smp_processor_id()) |
936 | spin_unlock_bh(&iucv_table_lock); | 984 | spin_unlock_bh(&iucv_table_lock); |
985 | out: | ||
937 | preempt_enable(); | 986 | preempt_enable(); |
938 | return rc; | 987 | return rc; |
939 | } | 988 | } |
@@ -956,6 +1005,10 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
956 | int rc; | 1005 | int rc; |
957 | 1006 | ||
958 | local_bh_disable(); | 1007 | local_bh_disable(); |
1008 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1009 | rc = -EIO; | ||
1010 | goto out; | ||
1011 | } | ||
959 | parm = iucv_param[smp_processor_id()]; | 1012 | parm = iucv_param[smp_processor_id()]; |
960 | memset(parm, 0, sizeof(union iucv_param)); | 1013 | memset(parm, 0, sizeof(union iucv_param)); |
961 | parm->purge.ippathid = path->pathid; | 1014 | parm->purge.ippathid = path->pathid; |
@@ -967,6 +1020,7 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
967 | msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; | 1020 | msg->audit = (*(u32 *) &parm->purge.ipaudit) >> 8; |
968 | msg->tag = parm->purge.ipmsgtag; | 1021 | msg->tag = parm->purge.ipmsgtag; |
969 | } | 1022 | } |
1023 | out: | ||
970 | local_bh_enable(); | 1024 | local_bh_enable(); |
971 | return rc; | 1025 | return rc; |
972 | } | 1026 | } |
@@ -1043,6 +1097,10 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
1043 | if (msg->flags & IUCV_IPRMDATA) | 1097 | if (msg->flags & IUCV_IPRMDATA) |
1044 | return iucv_message_receive_iprmdata(path, msg, flags, | 1098 | return iucv_message_receive_iprmdata(path, msg, flags, |
1045 | buffer, size, residual); | 1099 | buffer, size, residual); |
1100 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1101 | rc = -EIO; | ||
1102 | goto out; | ||
1103 | } | ||
1046 | parm = iucv_param[smp_processor_id()]; | 1104 | parm = iucv_param[smp_processor_id()]; |
1047 | memset(parm, 0, sizeof(union iucv_param)); | 1105 | memset(parm, 0, sizeof(union iucv_param)); |
1048 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; | 1106 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
@@ -1058,6 +1116,7 @@ int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
1058 | if (residual) | 1116 | if (residual) |
1059 | *residual = parm->db.ipbfln1f; | 1117 | *residual = parm->db.ipbfln1f; |
1060 | } | 1118 | } |
1119 | out: | ||
1061 | return rc; | 1120 | return rc; |
1062 | } | 1121 | } |
1063 | EXPORT_SYMBOL(__iucv_message_receive); | 1122 | EXPORT_SYMBOL(__iucv_message_receive); |
@@ -1111,6 +1170,10 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) | |||
1111 | int rc; | 1170 | int rc; |
1112 | 1171 | ||
1113 | local_bh_disable(); | 1172 | local_bh_disable(); |
1173 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1174 | rc = -EIO; | ||
1175 | goto out; | ||
1176 | } | ||
1114 | parm = iucv_param[smp_processor_id()]; | 1177 | parm = iucv_param[smp_processor_id()]; |
1115 | memset(parm, 0, sizeof(union iucv_param)); | 1178 | memset(parm, 0, sizeof(union iucv_param)); |
1116 | parm->db.ippathid = path->pathid; | 1179 | parm->db.ippathid = path->pathid; |
@@ -1118,6 +1181,7 @@ int iucv_message_reject(struct iucv_path *path, struct iucv_message *msg) | |||
1118 | parm->db.iptrgcls = msg->class; | 1181 | parm->db.iptrgcls = msg->class; |
1119 | parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); | 1182 | parm->db.ipflags1 = (IUCV_IPTRGCLS | IUCV_IPFGMID | IUCV_IPFGPID); |
1120 | rc = iucv_call_b2f0(IUCV_REJECT, parm); | 1183 | rc = iucv_call_b2f0(IUCV_REJECT, parm); |
1184 | out: | ||
1121 | local_bh_enable(); | 1185 | local_bh_enable(); |
1122 | return rc; | 1186 | return rc; |
1123 | } | 1187 | } |
@@ -1145,6 +1209,10 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
1145 | int rc; | 1209 | int rc; |
1146 | 1210 | ||
1147 | local_bh_disable(); | 1211 | local_bh_disable(); |
1212 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1213 | rc = -EIO; | ||
1214 | goto out; | ||
1215 | } | ||
1148 | parm = iucv_param[smp_processor_id()]; | 1216 | parm = iucv_param[smp_processor_id()]; |
1149 | memset(parm, 0, sizeof(union iucv_param)); | 1217 | memset(parm, 0, sizeof(union iucv_param)); |
1150 | if (flags & IUCV_IPRMDATA) { | 1218 | if (flags & IUCV_IPRMDATA) { |
@@ -1162,6 +1230,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
1162 | parm->db.iptrgcls = msg->class; | 1230 | parm->db.iptrgcls = msg->class; |
1163 | } | 1231 | } |
1164 | rc = iucv_call_b2f0(IUCV_REPLY, parm); | 1232 | rc = iucv_call_b2f0(IUCV_REPLY, parm); |
1233 | out: | ||
1165 | local_bh_enable(); | 1234 | local_bh_enable(); |
1166 | return rc; | 1235 | return rc; |
1167 | } | 1236 | } |
@@ -1190,6 +1259,10 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
1190 | union iucv_param *parm; | 1259 | union iucv_param *parm; |
1191 | int rc; | 1260 | int rc; |
1192 | 1261 | ||
1262 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1263 | rc = -EIO; | ||
1264 | goto out; | ||
1265 | } | ||
1193 | parm = iucv_param[smp_processor_id()]; | 1266 | parm = iucv_param[smp_processor_id()]; |
1194 | memset(parm, 0, sizeof(union iucv_param)); | 1267 | memset(parm, 0, sizeof(union iucv_param)); |
1195 | if (flags & IUCV_IPRMDATA) { | 1268 | if (flags & IUCV_IPRMDATA) { |
@@ -1212,6 +1285,7 @@ int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
1212 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1285 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
1213 | if (!rc) | 1286 | if (!rc) |
1214 | msg->id = parm->db.ipmsgid; | 1287 | msg->id = parm->db.ipmsgid; |
1288 | out: | ||
1215 | return rc; | 1289 | return rc; |
1216 | } | 1290 | } |
1217 | EXPORT_SYMBOL(__iucv_message_send); | 1291 | EXPORT_SYMBOL(__iucv_message_send); |
@@ -1272,6 +1346,10 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, | |||
1272 | int rc; | 1346 | int rc; |
1273 | 1347 | ||
1274 | local_bh_disable(); | 1348 | local_bh_disable(); |
1349 | if (!cpu_isset(smp_processor_id(), iucv_buffer_cpumask)) { | ||
1350 | rc = -EIO; | ||
1351 | goto out; | ||
1352 | } | ||
1275 | parm = iucv_param[smp_processor_id()]; | 1353 | parm = iucv_param[smp_processor_id()]; |
1276 | memset(parm, 0, sizeof(union iucv_param)); | 1354 | memset(parm, 0, sizeof(union iucv_param)); |
1277 | if (flags & IUCV_IPRMDATA) { | 1355 | if (flags & IUCV_IPRMDATA) { |
@@ -1297,6 +1375,7 @@ int iucv_message_send2way(struct iucv_path *path, struct iucv_message *msg, | |||
1297 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1375 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
1298 | if (!rc) | 1376 | if (!rc) |
1299 | msg->id = parm->db.ipmsgid; | 1377 | msg->id = parm->db.ipmsgid; |
1378 | out: | ||
1300 | local_bh_enable(); | 1379 | local_bh_enable(); |
1301 | return rc; | 1380 | return rc; |
1302 | } | 1381 | } |
@@ -1740,15 +1819,20 @@ static int __init iucv_init(void) | |||
1740 | rc = register_hotcpu_notifier(&iucv_cpu_notifier); | 1819 | rc = register_hotcpu_notifier(&iucv_cpu_notifier); |
1741 | if (rc) | 1820 | if (rc) |
1742 | goto out_free; | 1821 | goto out_free; |
1822 | rc = register_reboot_notifier(&iucv_reboot_notifier); | ||
1823 | if (rc) | ||
1824 | goto out_cpu; | ||
1743 | ASCEBC(iucv_error_no_listener, 16); | 1825 | ASCEBC(iucv_error_no_listener, 16); |
1744 | ASCEBC(iucv_error_no_memory, 16); | 1826 | ASCEBC(iucv_error_no_memory, 16); |
1745 | ASCEBC(iucv_error_pathid, 16); | 1827 | ASCEBC(iucv_error_pathid, 16); |
1746 | iucv_available = 1; | 1828 | iucv_available = 1; |
1747 | rc = bus_register(&iucv_bus); | 1829 | rc = bus_register(&iucv_bus); |
1748 | if (rc) | 1830 | if (rc) |
1749 | goto out_cpu; | 1831 | goto out_reboot; |
1750 | return 0; | 1832 | return 0; |
1751 | 1833 | ||
1834 | out_reboot: | ||
1835 | unregister_reboot_notifier(&iucv_reboot_notifier); | ||
1752 | out_cpu: | 1836 | out_cpu: |
1753 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | 1837 | unregister_hotcpu_notifier(&iucv_cpu_notifier); |
1754 | out_free: | 1838 | out_free: |
@@ -1783,6 +1867,7 @@ static void __exit iucv_exit(void) | |||
1783 | list_for_each_entry_safe(p, n, &iucv_work_queue, list) | 1867 | list_for_each_entry_safe(p, n, &iucv_work_queue, list) |
1784 | kfree(p); | 1868 | kfree(p); |
1785 | spin_unlock_irq(&iucv_queue_lock); | 1869 | spin_unlock_irq(&iucv_queue_lock); |
1870 | unregister_reboot_notifier(&iucv_reboot_notifier); | ||
1786 | unregister_hotcpu_notifier(&iucv_cpu_notifier); | 1871 | unregister_hotcpu_notifier(&iucv_cpu_notifier); |
1787 | for_each_possible_cpu(cpu) { | 1872 | for_each_possible_cpu(cpu) { |
1788 | kfree(iucv_param_irq[cpu]); | 1873 | kfree(iucv_param_irq[cpu]); |