[AF_IUCV]: Add lock when updating accept_q

The accept_queue of an af_iucv socket will be corrupted, if
adding and deleting of entries in this queue occurs at the
same time (connect request from one client, while accept call
is processed for another client).
Solution: add locking when updating accept_q

Signed-off-by: Ursula Braun <braunu@de.ibm.com>
Acked-by: Frank Pavlic <fpavlic@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c
index d9e9ddb..53ae14c 100644
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -219,6 +219,7 @@
 
 	sock_init_data(sock, sk);
 	INIT_LIST_HEAD(&iucv_sk(sk)->accept_q);
+	spin_lock_init(&iucv_sk(sk)->accept_q_lock);
 	skb_queue_head_init(&iucv_sk(sk)->send_skb_q);
 	skb_queue_head_init(&iucv_sk(sk)->backlog_skb_q);
 	iucv_sk(sk)->send_tag = 0;
@@ -274,15 +275,25 @@
 
 void iucv_accept_enqueue(struct sock *parent, struct sock *sk)
 {
+	unsigned long flags;
+	struct iucv_sock *par = iucv_sk(parent);
+
 	sock_hold(sk);
-	list_add_tail(&iucv_sk(sk)->accept_q, &iucv_sk(parent)->accept_q);
+	spin_lock_irqsave(&par->accept_q_lock, flags);
+	list_add_tail(&iucv_sk(sk)->accept_q, &par->accept_q);
+	spin_unlock_irqrestore(&par->accept_q_lock, flags);
 	iucv_sk(sk)->parent = parent;
 	parent->sk_ack_backlog++;
 }
 
 void iucv_accept_unlink(struct sock *sk)
 {
+	unsigned long flags;
+	struct iucv_sock *par = iucv_sk(iucv_sk(sk)->parent);
+
+	spin_lock_irqsave(&par->accept_q_lock, flags);
 	list_del_init(&iucv_sk(sk)->accept_q);
+	spin_unlock_irqrestore(&par->accept_q_lock, flags);
 	iucv_sk(sk)->parent->sk_ack_backlog--;
 	iucv_sk(sk)->parent = NULL;
 	sock_put(sk);
@@ -298,8 +309,8 @@
 		lock_sock(sk);
 
 		if (sk->sk_state == IUCV_CLOSED) {
-			release_sock(sk);
 			iucv_accept_unlink(sk);
+			release_sock(sk);
 			continue;
 		}
 
@@ -879,6 +890,7 @@
 	/* Find out if this path belongs to af_iucv. */
 	read_lock(&iucv_sk_list.lock);
 	iucv = NULL;
+	sk = NULL;
 	sk_for_each(sk, node, &iucv_sk_list.head)
 		if (sk->sk_state == IUCV_LISTEN &&
 		    !memcmp(&iucv_sk(sk)->src_name, src_name, 8)) {