diff options
author | Hendrik Brueckner <brueckner@linux.vnet.ibm.com> | 2008-12-25 07:38:58 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:39:04 -0500 |
commit | 91d5d45ee0a8978870fd12e5c3fe394a530ec2ed (patch) | |
tree | 2849fa4ce5110341627f76ac1fe36289fff27154 | |
parent | 44a01d5ba8a4d543694461cd3e178cfa6b3f221b (diff) |
[S390] iucv: Locking free version of iucv_message_(receive|send)
Provide a locking free version of iucv_message_receive and iucv_message_send
that do not call local_bh_enable in a spin_lock_(bh|irqsave)() context.
Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
-rw-r--r-- | include/net/iucv/iucv.h | 45 | ||||
-rw-r--r-- | net/iucv/iucv.c | 152 |
2 files changed, 161 insertions, 36 deletions
diff --git a/include/net/iucv/iucv.h b/include/net/iucv/iucv.h index fd70adbb3566..5e310c8d8e2f 100644 --- a/include/net/iucv/iucv.h +++ b/include/net/iucv/iucv.h | |||
@@ -337,12 +337,35 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
337 | * established paths. This function will deal with RMDATA messages | 337 | * established paths. This function will deal with RMDATA messages |
338 | * embedded in struct iucv_message as well. | 338 | * embedded in struct iucv_message as well. |
339 | * | 339 | * |
340 | * Locking: local_bh_enable/local_bh_disable | ||
341 | * | ||
340 | * Returns the result from the CP IUCV call. | 342 | * Returns the result from the CP IUCV call. |
341 | */ | 343 | */ |
342 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | 344 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, |
343 | u8 flags, void *buffer, size_t size, size_t *residual); | 345 | u8 flags, void *buffer, size_t size, size_t *residual); |
344 | 346 | ||
345 | /** | 347 | /** |
348 | * __iucv_message_receive | ||
349 | * @path: address of iucv path structure | ||
350 | * @msg: address of iucv msg structure | ||
351 | * @flags: flags that affect how the message is received (IUCV_IPBUFLST) | ||
352 | * @buffer: address of data buffer or address of struct iucv_array | ||
353 | * @size: length of data buffer | ||
354 | * @residual: | ||
355 | * | ||
356 | * This function receives messages that are being sent to you over | ||
357 | * established paths. This function will deal with RMDATA messages | ||
358 | * embedded in struct iucv_message as well. | ||
359 | * | ||
360 | * Locking: no locking. | ||
361 | * | ||
362 | * Returns the result from the CP IUCV call. | ||
363 | */ | ||
364 | int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | ||
365 | u8 flags, void *buffer, size_t size, | ||
366 | size_t *residual); | ||
367 | |||
368 | /** | ||
346 | * iucv_message_reject | 369 | * iucv_message_reject |
347 | * @path: address of iucv path structure | 370 | * @path: address of iucv path structure |
348 | * @msg: address of iucv msg structure | 371 | * @msg: address of iucv msg structure |
@@ -386,12 +409,34 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
386 | * transmitted is in a buffer and this is a one-way message and the | 409 | * transmitted is in a buffer and this is a one-way message and the |
387 | * receiver will not reply to the message. | 410 | * receiver will not reply to the message. |
388 | * | 411 | * |
412 | * Locking: local_bh_enable/local_bh_disable | ||
413 | * | ||
389 | * Returns the result from the CP IUCV call. | 414 | * Returns the result from the CP IUCV call. |
390 | */ | 415 | */ |
391 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | 416 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, |
392 | u8 flags, u32 srccls, void *buffer, size_t size); | 417 | u8 flags, u32 srccls, void *buffer, size_t size); |
393 | 418 | ||
394 | /** | 419 | /** |
420 | * __iucv_message_send | ||
421 | * @path: address of iucv path structure | ||
422 | * @msg: address of iucv msg structure | ||
423 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) | ||
424 | * @srccls: source class of message | ||
425 | * @buffer: address of data buffer or address of struct iucv_array | ||
426 | * @size: length of send buffer | ||
427 | * | ||
428 | * This function transmits data to another application. Data to be | ||
429 | * transmitted is in a buffer and this is a one-way message and the | ||
430 | * receiver will not reply to the message. | ||
431 | * | ||
432 | * Locking: no locking. | ||
433 | * | ||
434 | * Returns the result from the CP IUCV call. | ||
435 | */ | ||
436 | int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | ||
437 | u8 flags, u32 srccls, void *buffer, size_t size); | ||
438 | |||
439 | /** | ||
395 | * iucv_message_send2way | 440 | * iucv_message_send2way |
396 | * @path: address of iucv path structure | 441 | * @path: address of iucv path structure |
397 | * @msg: address of iucv msg structure | 442 | * @msg: address of iucv msg structure |
diff --git a/net/iucv/iucv.c b/net/iucv/iucv.c index d7b54b5bfa69..6bf51f7e597f 100644 --- a/net/iucv/iucv.c +++ b/net/iucv/iucv.c | |||
@@ -957,7 +957,52 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg, | |||
957 | EXPORT_SYMBOL(iucv_message_purge); | 957 | EXPORT_SYMBOL(iucv_message_purge); |
958 | 958 | ||
959 | /** | 959 | /** |
960 | * iucv_message_receive | 960 | * iucv_message_receive_iprmdata |
961 | * @path: address of iucv path structure | ||
962 | * @msg: address of iucv msg structure | ||
963 | * @flags: how the message is received (IUCV_IPBUFLST) | ||
964 | * @buffer: address of data buffer or address of struct iucv_array | ||
965 | * @size: length of data buffer | ||
966 | * @residual: | ||
967 | * | ||
968 | * Internal function used by iucv_message_receive and __iucv_message_receive | ||
969 | * to receive RMDATA data stored in struct iucv_message. | ||
970 | */ | ||
971 | static int iucv_message_receive_iprmdata(struct iucv_path *path, | ||
972 | struct iucv_message *msg, | ||
973 | u8 flags, void *buffer, | ||
974 | size_t size, size_t *residual) | ||
975 | { | ||
976 | struct iucv_array *array; | ||
977 | u8 *rmmsg; | ||
978 | size_t copy; | ||
979 | |||
980 | /* | ||
981 | * Message is 8 bytes long and has been stored to the | ||
982 | * message descriptor itself. | ||
983 | */ | ||
984 | if (residual) | ||
985 | *residual = abs(size - 8); | ||
986 | rmmsg = msg->rmmsg; | ||
987 | if (flags & IUCV_IPBUFLST) { | ||
988 | /* Copy to struct iucv_array. */ | ||
989 | size = (size < 8) ? size : 8; | ||
990 | for (array = buffer; size > 0; array++) { | ||
991 | copy = min_t(size_t, size, array->length); | ||
992 | memcpy((u8 *)(addr_t) array->address, | ||
993 | rmmsg, copy); | ||
994 | rmmsg += copy; | ||
995 | size -= copy; | ||
996 | } | ||
997 | } else { | ||
998 | /* Copy to direct buffer. */ | ||
999 | memcpy(buffer, rmmsg, min_t(size_t, size, 8)); | ||
1000 | } | ||
1001 | return 0; | ||
1002 | } | ||
1003 | |||
1004 | /** | ||
1005 | * __iucv_message_receive | ||
961 | * @path: address of iucv path structure | 1006 | * @path: address of iucv path structure |
962 | * @msg: address of iucv msg structure | 1007 | * @msg: address of iucv msg structure |
963 | * @flags: how the message is received (IUCV_IPBUFLST) | 1008 | * @flags: how the message is received (IUCV_IPBUFLST) |
@@ -969,44 +1014,19 @@ EXPORT_SYMBOL(iucv_message_purge); | |||
969 | * established paths. This function will deal with RMDATA messages | 1014 | * established paths. This function will deal with RMDATA messages |
970 | * embedded in struct iucv_message as well. | 1015 | * embedded in struct iucv_message as well. |
971 | * | 1016 | * |
1017 | * Locking: no locking | ||
1018 | * | ||
972 | * Returns the result from the CP IUCV call. | 1019 | * Returns the result from the CP IUCV call. |
973 | */ | 1020 | */ |
974 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | 1021 | int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, |
975 | u8 flags, void *buffer, size_t size, size_t *residual) | 1022 | u8 flags, void *buffer, size_t size, size_t *residual) |
976 | { | 1023 | { |
977 | union iucv_param *parm; | 1024 | union iucv_param *parm; |
978 | struct iucv_array *array; | ||
979 | u8 *rmmsg; | ||
980 | size_t copy; | ||
981 | int rc; | 1025 | int rc; |
982 | 1026 | ||
983 | if (msg->flags & IUCV_IPRMDATA) { | 1027 | if (msg->flags & IUCV_IPRMDATA) |
984 | /* | 1028 | return iucv_message_receive_iprmdata(path, msg, flags, |
985 | * Message is 8 bytes long and has been stored to the | 1029 | buffer, size, residual); |
986 | * message descriptor itself. | ||
987 | */ | ||
988 | rc = (size < 8) ? 5 : 0; | ||
989 | if (residual) | ||
990 | *residual = abs(size - 8); | ||
991 | rmmsg = msg->rmmsg; | ||
992 | if (flags & IUCV_IPBUFLST) { | ||
993 | /* Copy to struct iucv_array. */ | ||
994 | size = (size < 8) ? size : 8; | ||
995 | for (array = buffer; size > 0; array++) { | ||
996 | copy = min_t(size_t, size, array->length); | ||
997 | memcpy((u8 *)(addr_t) array->address, | ||
998 | rmmsg, copy); | ||
999 | rmmsg += copy; | ||
1000 | size -= copy; | ||
1001 | } | ||
1002 | } else { | ||
1003 | /* Copy to direct buffer. */ | ||
1004 | memcpy(buffer, rmmsg, min_t(size_t, size, 8)); | ||
1005 | } | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | local_bh_disable(); | ||
1010 | parm = iucv_param[smp_processor_id()]; | 1030 | parm = iucv_param[smp_processor_id()]; |
1011 | memset(parm, 0, sizeof(union iucv_param)); | 1031 | memset(parm, 0, sizeof(union iucv_param)); |
1012 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; | 1032 | parm->db.ipbfadr1 = (u32)(addr_t) buffer; |
@@ -1022,6 +1042,37 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | |||
1022 | if (residual) | 1042 | if (residual) |
1023 | *residual = parm->db.ipbfln1f; | 1043 | *residual = parm->db.ipbfln1f; |
1024 | } | 1044 | } |
1045 | return rc; | ||
1046 | } | ||
1047 | EXPORT_SYMBOL(__iucv_message_receive); | ||
1048 | |||
1049 | /** | ||
1050 | * iucv_message_receive | ||
1051 | * @path: address of iucv path structure | ||
1052 | * @msg: address of iucv msg structure | ||
1053 | * @flags: how the message is received (IUCV_IPBUFLST) | ||
1054 | * @buffer: address of data buffer or address of struct iucv_array | ||
1055 | * @size: length of data buffer | ||
1056 | * @residual: | ||
1057 | * | ||
1058 | * This function receives messages that are being sent to you over | ||
1059 | * established paths. This function will deal with RMDATA messages | ||
1060 | * embedded in struct iucv_message as well. | ||
1061 | * | ||
1062 | * Locking: local_bh_enable/local_bh_disable | ||
1063 | * | ||
1064 | * Returns the result from the CP IUCV call. | ||
1065 | */ | ||
1066 | int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, | ||
1067 | u8 flags, void *buffer, size_t size, size_t *residual) | ||
1068 | { | ||
1069 | int rc; | ||
1070 | |||
1071 | if (msg->flags & IUCV_IPRMDATA) | ||
1072 | return iucv_message_receive_iprmdata(path, msg, flags, | ||
1073 | buffer, size, residual); | ||
1074 | local_bh_disable(); | ||
1075 | rc = __iucv_message_receive(path, msg, flags, buffer, size, residual); | ||
1025 | local_bh_enable(); | 1076 | local_bh_enable(); |
1026 | return rc; | 1077 | return rc; |
1027 | } | 1078 | } |
@@ -1101,7 +1152,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg, | |||
1101 | EXPORT_SYMBOL(iucv_message_reply); | 1152 | EXPORT_SYMBOL(iucv_message_reply); |
1102 | 1153 | ||
1103 | /** | 1154 | /** |
1104 | * iucv_message_send | 1155 | * __iucv_message_send |
1105 | * @path: address of iucv path structure | 1156 | * @path: address of iucv path structure |
1106 | * @msg: address of iucv msg structure | 1157 | * @msg: address of iucv msg structure |
1107 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) | 1158 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) |
@@ -1113,15 +1164,16 @@ EXPORT_SYMBOL(iucv_message_reply); | |||
1113 | * transmitted is in a buffer and this is a one-way message and the | 1164 | * transmitted is in a buffer and this is a one-way message and the |
1114 | * receiver will not reply to the message. | 1165 | * receiver will not reply to the message. |
1115 | * | 1166 | * |
1167 | * Locking: no locking | ||
1168 | * | ||
1116 | * Returns the result from the CP IUCV call. | 1169 | * Returns the result from the CP IUCV call. |
1117 | */ | 1170 | */ |
1118 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | 1171 | int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg, |
1119 | u8 flags, u32 srccls, void *buffer, size_t size) | 1172 | u8 flags, u32 srccls, void *buffer, size_t size) |
1120 | { | 1173 | { |
1121 | union iucv_param *parm; | 1174 | union iucv_param *parm; |
1122 | int rc; | 1175 | int rc; |
1123 | 1176 | ||
1124 | local_bh_disable(); | ||
1125 | parm = iucv_param[smp_processor_id()]; | 1177 | parm = iucv_param[smp_processor_id()]; |
1126 | memset(parm, 0, sizeof(union iucv_param)); | 1178 | memset(parm, 0, sizeof(union iucv_param)); |
1127 | if (flags & IUCV_IPRMDATA) { | 1179 | if (flags & IUCV_IPRMDATA) { |
@@ -1144,6 +1196,34 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | |||
1144 | rc = iucv_call_b2f0(IUCV_SEND, parm); | 1196 | rc = iucv_call_b2f0(IUCV_SEND, parm); |
1145 | if (!rc) | 1197 | if (!rc) |
1146 | msg->id = parm->db.ipmsgid; | 1198 | msg->id = parm->db.ipmsgid; |
1199 | return rc; | ||
1200 | } | ||
1201 | EXPORT_SYMBOL(__iucv_message_send); | ||
1202 | |||
1203 | /** | ||
1204 | * iucv_message_send | ||
1205 | * @path: address of iucv path structure | ||
1206 | * @msg: address of iucv msg structure | ||
1207 | * @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST) | ||
1208 | * @srccls: source class of message | ||
1209 | * @buffer: address of send buffer or address of struct iucv_array | ||
1210 | * @size: length of send buffer | ||
1211 | * | ||
1212 | * This function transmits data to another application. Data to be | ||
1213 | * transmitted is in a buffer and this is a one-way message and the | ||
1214 | * receiver will not reply to the message. | ||
1215 | * | ||
1216 | * Locking: local_bh_enable/local_bh_disable | ||
1217 | * | ||
1218 | * Returns the result from the CP IUCV call. | ||
1219 | */ | ||
1220 | int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, | ||
1221 | u8 flags, u32 srccls, void *buffer, size_t size) | ||
1222 | { | ||
1223 | int rc; | ||
1224 | |||
1225 | local_bh_disable(); | ||
1226 | rc = __iucv_message_send(path, msg, flags, srccls, buffer, size); | ||
1147 | local_bh_enable(); | 1227 | local_bh_enable(); |
1148 | return rc; | 1228 | return rc; |
1149 | } | 1229 | } |