forked from luck/tmp_suning_uos_patched
[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>
This commit is contained in:
parent
44a01d5ba8
commit
91d5d45ee0
|
@ -337,11 +337,34 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
|
|||
* established paths. This function will deal with RMDATA messages
|
||||
* embedded in struct iucv_message as well.
|
||||
*
|
||||
* Locking: local_bh_enable/local_bh_disable
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, void *buffer, size_t size, size_t *residual);
|
||||
|
||||
/**
|
||||
* __iucv_message_receive
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: flags that affect how the message is received (IUCV_IPBUFLST)
|
||||
* @buffer: address of data buffer or address of struct iucv_array
|
||||
* @size: length of data buffer
|
||||
* @residual:
|
||||
*
|
||||
* This function receives messages that are being sent to you over
|
||||
* established paths. This function will deal with RMDATA messages
|
||||
* embedded in struct iucv_message as well.
|
||||
*
|
||||
* Locking: no locking.
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, void *buffer, size_t size,
|
||||
size_t *residual);
|
||||
|
||||
/**
|
||||
* iucv_message_reject
|
||||
* @path: address of iucv path structure
|
||||
|
@ -386,11 +409,33 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
|
|||
* transmitted is in a buffer and this is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
*
|
||||
* Locking: local_bh_enable/local_bh_disable
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, u32 srccls, void *buffer, size_t size);
|
||||
|
||||
/**
|
||||
* __iucv_message_send
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
|
||||
* @srccls: source class of message
|
||||
* @buffer: address of data buffer or address of struct iucv_array
|
||||
* @size: length of send buffer
|
||||
*
|
||||
* This function transmits data to another application. Data to be
|
||||
* transmitted is in a buffer and this is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
*
|
||||
* Locking: no locking.
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, u32 srccls, void *buffer, size_t size);
|
||||
|
||||
/**
|
||||
* iucv_message_send2way
|
||||
* @path: address of iucv path structure
|
||||
|
|
152
net/iucv/iucv.c
152
net/iucv/iucv.c
|
@ -957,7 +957,52 @@ int iucv_message_purge(struct iucv_path *path, struct iucv_message *msg,
|
|||
EXPORT_SYMBOL(iucv_message_purge);
|
||||
|
||||
/**
|
||||
* iucv_message_receive
|
||||
* iucv_message_receive_iprmdata
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is received (IUCV_IPBUFLST)
|
||||
* @buffer: address of data buffer or address of struct iucv_array
|
||||
* @size: length of data buffer
|
||||
* @residual:
|
||||
*
|
||||
* Internal function used by iucv_message_receive and __iucv_message_receive
|
||||
* to receive RMDATA data stored in struct iucv_message.
|
||||
*/
|
||||
static int iucv_message_receive_iprmdata(struct iucv_path *path,
|
||||
struct iucv_message *msg,
|
||||
u8 flags, void *buffer,
|
||||
size_t size, size_t *residual)
|
||||
{
|
||||
struct iucv_array *array;
|
||||
u8 *rmmsg;
|
||||
size_t copy;
|
||||
|
||||
/*
|
||||
* Message is 8 bytes long and has been stored to the
|
||||
* message descriptor itself.
|
||||
*/
|
||||
if (residual)
|
||||
*residual = abs(size - 8);
|
||||
rmmsg = msg->rmmsg;
|
||||
if (flags & IUCV_IPBUFLST) {
|
||||
/* Copy to struct iucv_array. */
|
||||
size = (size < 8) ? size : 8;
|
||||
for (array = buffer; size > 0; array++) {
|
||||
copy = min_t(size_t, size, array->length);
|
||||
memcpy((u8 *)(addr_t) array->address,
|
||||
rmmsg, copy);
|
||||
rmmsg += copy;
|
||||
size -= copy;
|
||||
}
|
||||
} else {
|
||||
/* Copy to direct buffer. */
|
||||
memcpy(buffer, rmmsg, min_t(size_t, size, 8));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* __iucv_message_receive
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is received (IUCV_IPBUFLST)
|
||||
|
@ -969,44 +1014,19 @@ EXPORT_SYMBOL(iucv_message_purge);
|
|||
* established paths. This function will deal with RMDATA messages
|
||||
* embedded in struct iucv_message as well.
|
||||
*
|
||||
* Locking: no locking
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, void *buffer, size_t size, size_t *residual)
|
||||
int __iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, void *buffer, size_t size, size_t *residual)
|
||||
{
|
||||
union iucv_param *parm;
|
||||
struct iucv_array *array;
|
||||
u8 *rmmsg;
|
||||
size_t copy;
|
||||
int rc;
|
||||
|
||||
if (msg->flags & IUCV_IPRMDATA) {
|
||||
/*
|
||||
* Message is 8 bytes long and has been stored to the
|
||||
* message descriptor itself.
|
||||
*/
|
||||
rc = (size < 8) ? 5 : 0;
|
||||
if (residual)
|
||||
*residual = abs(size - 8);
|
||||
rmmsg = msg->rmmsg;
|
||||
if (flags & IUCV_IPBUFLST) {
|
||||
/* Copy to struct iucv_array. */
|
||||
size = (size < 8) ? size : 8;
|
||||
for (array = buffer; size > 0; array++) {
|
||||
copy = min_t(size_t, size, array->length);
|
||||
memcpy((u8 *)(addr_t) array->address,
|
||||
rmmsg, copy);
|
||||
rmmsg += copy;
|
||||
size -= copy;
|
||||
}
|
||||
} else {
|
||||
/* Copy to direct buffer. */
|
||||
memcpy(buffer, rmmsg, min_t(size_t, size, 8));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
local_bh_disable();
|
||||
if (msg->flags & IUCV_IPRMDATA)
|
||||
return iucv_message_receive_iprmdata(path, msg, flags,
|
||||
buffer, size, residual);
|
||||
parm = iucv_param[smp_processor_id()];
|
||||
memset(parm, 0, sizeof(union iucv_param));
|
||||
parm->db.ipbfadr1 = (u32)(addr_t) buffer;
|
||||
|
@ -1022,6 +1042,37 @@ int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
|||
if (residual)
|
||||
*residual = parm->db.ipbfln1f;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(__iucv_message_receive);
|
||||
|
||||
/**
|
||||
* iucv_message_receive
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is received (IUCV_IPBUFLST)
|
||||
* @buffer: address of data buffer or address of struct iucv_array
|
||||
* @size: length of data buffer
|
||||
* @residual:
|
||||
*
|
||||
* This function receives messages that are being sent to you over
|
||||
* established paths. This function will deal with RMDATA messages
|
||||
* embedded in struct iucv_message as well.
|
||||
*
|
||||
* Locking: local_bh_enable/local_bh_disable
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_receive(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, void *buffer, size_t size, size_t *residual)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (msg->flags & IUCV_IPRMDATA)
|
||||
return iucv_message_receive_iprmdata(path, msg, flags,
|
||||
buffer, size, residual);
|
||||
local_bh_disable();
|
||||
rc = __iucv_message_receive(path, msg, flags, buffer, size, residual);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
}
|
||||
|
@ -1101,7 +1152,7 @@ int iucv_message_reply(struct iucv_path *path, struct iucv_message *msg,
|
|||
EXPORT_SYMBOL(iucv_message_reply);
|
||||
|
||||
/**
|
||||
* iucv_message_send
|
||||
* __iucv_message_send
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
|
||||
|
@ -1113,15 +1164,16 @@ EXPORT_SYMBOL(iucv_message_reply);
|
|||
* transmitted is in a buffer and this is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
*
|
||||
* Locking: no locking
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
||||
int __iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, u32 srccls, void *buffer, size_t size)
|
||||
{
|
||||
union iucv_param *parm;
|
||||
int rc;
|
||||
|
||||
local_bh_disable();
|
||||
parm = iucv_param[smp_processor_id()];
|
||||
memset(parm, 0, sizeof(union iucv_param));
|
||||
if (flags & IUCV_IPRMDATA) {
|
||||
|
@ -1144,6 +1196,34 @@ int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
|||
rc = iucv_call_b2f0(IUCV_SEND, parm);
|
||||
if (!rc)
|
||||
msg->id = parm->db.ipmsgid;
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(__iucv_message_send);
|
||||
|
||||
/**
|
||||
* iucv_message_send
|
||||
* @path: address of iucv path structure
|
||||
* @msg: address of iucv msg structure
|
||||
* @flags: how the message is sent (IUCV_IPRMDATA, IUCV_IPPRTY, IUCV_IPBUFLST)
|
||||
* @srccls: source class of message
|
||||
* @buffer: address of send buffer or address of struct iucv_array
|
||||
* @size: length of send buffer
|
||||
*
|
||||
* This function transmits data to another application. Data to be
|
||||
* transmitted is in a buffer and this is a one-way message and the
|
||||
* receiver will not reply to the message.
|
||||
*
|
||||
* Locking: local_bh_enable/local_bh_disable
|
||||
*
|
||||
* Returns the result from the CP IUCV call.
|
||||
*/
|
||||
int iucv_message_send(struct iucv_path *path, struct iucv_message *msg,
|
||||
u8 flags, u32 srccls, void *buffer, size_t size)
|
||||
{
|
||||
int rc;
|
||||
|
||||
local_bh_disable();
|
||||
rc = __iucv_message_send(path, msg, flags, srccls, buffer, size);
|
||||
local_bh_enable();
|
||||
return rc;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user