aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHendrik Brueckner <brueckner@linux.vnet.ibm.com>2009-04-21 06:04:24 +0000
committerDavid S. Miller <davem@davemloft.net>2009-04-21 23:43:15 -0700
commit3fa6b5adbe46b3d665267dee0f879858ab464f44 (patch)
tree4c526871b0195570f9844e6e586611c1fa4731e8
parente14ad5fa8705fb354e72312479abbe420ebc3f8e (diff)
af_iucv: Fix race when queuing incoming iucv messages
AF_IUCV runs into a race when queuing incoming iucv messages and receiving the resulting backlog. If the Linux system is under pressure (high load or steal time), the message queue grows up, but messages are not received and queued onto the backlog queue. In that case, applications do not receive any data with recvmsg() even if AF_IUCV puts incoming messages onto the message queue. The race can be avoided if the message queue spinlock in the message_pending callback is spreaded across the entire callback function. Signed-off-by: Hendrik Brueckner <brueckner@linux.vnet.ibm.com> Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/iucv/af_iucv.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index 9cfdaaddc5b..b51c9187c34 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -1124,6 +1124,8 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
return;
}
+ spin_lock(&iucv->message_q.lock);
+
if (!list_empty(&iucv->message_q.list) ||
!skb_queue_empty(&iucv->backlog_skb_q))
goto save_message;
@@ -1137,9 +1139,8 @@ static void iucv_callback_rx(struct iucv_path *path, struct iucv_message *msg)
if (!skb)
goto save_message;
- spin_lock(&iucv->message_q.lock);
iucv_process_message(sk, skb, path, msg);
- spin_unlock(&iucv->message_q.lock);
+ goto out_unlock;
return;
@@ -1150,8 +1151,9 @@ save_message:
save_msg->path = path;
save_msg->msg = *msg;
- spin_lock(&iucv->message_q.lock);
list_add_tail(&save_msg->list, &iucv->message_q.list);
+
+out_unlock:
spin_unlock(&iucv->message_q.lock);
}