aboutsummaryrefslogtreecommitdiffstats
path: root/net/iucv/iucv.c
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2008-12-25 07:38:58 -0500
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2008-12-25 07:39:04 -0500
commit91d5d45ee0a8978870fd12e5c3fe394a530ec2ed (patch)
tree2849fa4ce5110341627f76ac1fe36289fff27154 /net/iucv/iucv.c
parent44a01d5ba8a4d543694461cd3e178cfa6b3f221b (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>
Diffstat (limited to 'net/iucv/iucv.c')
-rw-r--r--net/iucv/iucv.c152
1 files changed, 116 insertions, 36 deletions
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,
957EXPORT_SYMBOL(iucv_message_purge); 957EXPORT_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 */
971static 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 */
974int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg, 1021int __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}
1047EXPORT_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 */
1066int 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,
1101EXPORT_SYMBOL(iucv_message_reply); 1152EXPORT_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 */
1118int iucv_message_send(struct iucv_path *path, struct iucv_message *msg, 1171int __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}
1201EXPORT_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 */
1220int 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}