netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 00/10] s390: network driver features and fixes for net-next
@ 2011-12-20  8:56 frank.blaschka
  2011-12-20  8:56 ` [patch 01/10] [PATCH] af_iucv: support ancillary data with HS transport frank.blaschka
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390

Hi Dave,

here are some s390 network driver features and fixes for net-next

shortlog:

Ursula Braun (8)
af_iucv: support ancillary data with HS transport
af_iucv: accelerate close for HS transport
af_iucv: release reference to HS device
af_iucv: remove unused timer infrastructure
af_iucv: get rid of state IUCV_SEVERED
qeth: suspicious rcu_dereference_check in recovery
qeth: forbid recovery during shutdown
netiucv: allow multiple interfaces to same peer

Frank Blaschka (1)
qeth: improve recovery during resource shortage

Einar Lueck (1)
qeth: recovery through asynchronous delivery

Thanks,
        Frank

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 01/10] [PATCH] af_iucv: support ancillary data with HS transport
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 02/10] [PATCH] af_iucv: accelerate close for " frank.blaschka
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 600-af_iucv-ancillary-hs.diff --]
[-- Type: text/plain, Size: 670 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

The AF_IUCV address family offers support for ancillary data.
This patch enables usage of ancillary data with the new
HiperSockets transport.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 net/iucv/af_iucv.c |    2 ++
 1 file changed, 2 insertions(+)

--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -2209,6 +2209,8 @@ static int afiucv_hs_rcv(struct sk_buff
 		break;
 	case 0:
 		/* plain data frame */
+		memcpy(CB_TRGCLS(skb), &trans_hdr->iucv_hdr.class,
+		       CB_TRGCLS_LEN);
 		err = afiucv_hs_callback_rx(sk, skb);
 		break;
 	default:

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 02/10] [PATCH] af_iucv: accelerate close for HS transport
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
  2011-12-20  8:56 ` [patch 01/10] [PATCH] af_iucv: support ancillary data with HS transport frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 03/10] [PATCH] af_iucv: release reference to HS device frank.blaschka
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 601-af_iucv-fast-close-hs.diff --]
[-- Type: text/plain, Size: 751 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

Closing an af_iucv socket may wait for confirmation of outstanding
send requests. This patch adds confirmation code for the new
HiperSockets transport.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 net/iucv/af_iucv.c |    7 +++++++
 1 file changed, 7 insertions(+)

--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -2293,6 +2293,13 @@ static void afiucv_hs_callback_txnotify(
 	}
 	spin_unlock_irqrestore(&list->lock, flags);
 
+	if (sk->sk_state == IUCV_CLOSING) {
+		if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) {
+			sk->sk_state = IUCV_CLOSED;
+			sk->sk_state_change(sk);
+		}
+	}
+
 out_unlock:
 	bh_unlock_sock(sk);
 }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 03/10] [PATCH] af_iucv: release reference to HS device
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
  2011-12-20  8:56 ` [patch 01/10] [PATCH] af_iucv: support ancillary data with HS transport frank.blaschka
  2011-12-20  8:56 ` [patch 02/10] [PATCH] af_iucv: accelerate close for " frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 04/10] [PATCH] af_iucv: remove unused timer infrastructure frank.blaschka
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 602-af_iucv-release-skb-hs.diff --]
[-- Type: text/plain, Size: 4314 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

For HiperSockets transport skbs sent are bound to one of the
available HiperSockets devices. Add missing release of reference to
a HiperSockets device before freeing an skb.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 net/iucv/af_iucv.c |   37 ++++++++++++++++++++++++-------------
 1 file changed, 24 insertions(+), 13 deletions(-)

--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -130,6 +130,17 @@ static inline void low_nmcpy(unsigned ch
        memcpy(&dst[8], src, 8);
 }
 
+static void iucv_skb_queue_purge(struct sk_buff_head *list)
+{
+	struct sk_buff *skb;
+
+	while ((skb = skb_dequeue(list)) != NULL) {
+		if (skb->dev)
+			dev_put(skb->dev);
+		kfree_skb(skb);
+	}
+}
+
 static int afiucv_pm_prepare(struct device *dev)
 {
 #ifdef CONFIG_PM_DEBUG
@@ -164,7 +175,7 @@ static int afiucv_pm_freeze(struct devic
 	read_lock(&iucv_sk_list.lock);
 	sk_for_each(sk, node, &iucv_sk_list.head) {
 		iucv = iucv_sk(sk);
-		skb_queue_purge(&iucv->send_skb_q);
+		iucv_skb_queue_purge(&iucv->send_skb_q);
 		skb_queue_purge(&iucv->backlog_skb_q);
 		switch (sk->sk_state) {
 		case IUCV_SEVERED:
@@ -366,9 +377,7 @@ static int afiucv_hs_send(struct iucv_me
 	if (imsg)
 		memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message));
 
-	rcu_read_lock();
-	skb->dev = dev_get_by_index_rcu(net, sock->sk_bound_dev_if);
-	rcu_read_unlock();
+	skb->dev = dev_get_by_index(net, sock->sk_bound_dev_if);
 	if (!skb->dev)
 		return -ENODEV;
 	if (!(skb->dev->flags & IFF_UP))
@@ -388,6 +397,7 @@ static int afiucv_hs_send(struct iucv_me
 	err = dev_queue_xmit(skb);
 	if (err) {
 		skb_unlink(nskb, &iucv->send_skb_q);
+		dev_put(nskb->dev);
 		kfree_skb(nskb);
 	} else {
 		atomic_sub(confirm_recv, &iucv->msg_recv);
@@ -481,16 +491,14 @@ static void iucv_sock_close(struct sock
 			blen = sizeof(struct af_iucv_trans_hdr) + ETH_HLEN;
 			skb = sock_alloc_send_skb(sk, blen, 1, &err);
 			if (skb) {
-				skb_reserve(skb,
-					sizeof(struct af_iucv_trans_hdr) +
-					ETH_HLEN);
+				skb_reserve(skb, blen);
 				err = afiucv_hs_send(NULL, sk, skb,
 						     AF_IUCV_FLAG_FIN);
 			}
 			sk->sk_state = IUCV_DISCONN;
 			sk->sk_state_change(sk);
 		}
-	case IUCV_DISCONN:
+	case IUCV_DISCONN:   /* fall through */
 		sk->sk_state = IUCV_CLOSING;
 		sk->sk_state_change(sk);
 
@@ -520,7 +528,7 @@ static void iucv_sock_close(struct sock
 		sk->sk_err = ECONNRESET;
 		sk->sk_state_change(sk);
 
-		skb_queue_purge(&iucv->send_skb_q);
+		iucv_skb_queue_purge(&iucv->send_skb_q);
 		skb_queue_purge(&iucv->backlog_skb_q);
 		break;
 
@@ -739,7 +747,7 @@ static int iucv_sock_bind(struct socket
 		if (!memcmp(dev->perm_addr, uid, 8)) {
 			memcpy(iucv->src_name, sa->siucv_name, 8);
 			memcpy(iucv->src_user_id, sa->siucv_user_id, 8);
-			sock->sk->sk_bound_dev_if = dev->ifindex;
+			sk->sk_bound_dev_if = dev->ifindex;
 			sk->sk_state = IUCV_BOUND;
 			iucv->transport = AF_IUCV_TRANS_HIPER;
 			if (!iucv->msglimit)
@@ -1225,6 +1233,8 @@ release:
 	return len;
 
 fail:
+	if (skb->dev)
+		dev_put(skb->dev);
 	kfree_skb(skb);
 out:
 	release_sock(sk);
@@ -1441,9 +1451,7 @@ static int iucv_sock_recvmsg(struct kioc
 					ETH_HLEN;
 				sskb = sock_alloc_send_skb(sk, blen, 1, &err);
 				if (sskb) {
-					skb_reserve(sskb,
-						sizeof(struct af_iucv_trans_hdr)
-						+ ETH_HLEN);
+					skb_reserve(sskb, blen);
 					err = afiucv_hs_send(NULL, sk, sskb,
 							     AF_IUCV_FLAG_WIN);
 				}
@@ -2261,6 +2269,7 @@ static void afiucv_hs_callback_txnotify(
 			case TX_NOTIFY_OK:
 				__skb_unlink(this, list);
 				iucv_sock_wake_msglim(sk);
+				dev_put(this->dev);
 				kfree_skb(this);
 				break;
 			case TX_NOTIFY_PENDING:
@@ -2271,6 +2280,7 @@ static void afiucv_hs_callback_txnotify(
 				atomic_dec(&iucv->pendings);
 				if (atomic_read(&iucv->pendings) <= 0)
 					iucv_sock_wake_msglim(sk);
+				dev_put(this->dev);
 				kfree_skb(this);
 				break;
 			case TX_NOTIFY_UNREACHABLE:
@@ -2279,6 +2289,7 @@ static void afiucv_hs_callback_txnotify(
 			case TX_NOTIFY_GENERALERROR:
 			case TX_NOTIFY_DELAYED_GENERALERROR:
 				__skb_unlink(this, list);
+				dev_put(this->dev);
 				kfree_skb(this);
 				if (!list_empty(&iucv->accept_q))
 					sk->sk_state = IUCV_SEVERED;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 04/10] [PATCH] af_iucv: remove unused timer infrastructure
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (2 preceding siblings ...)
  2011-12-20  8:56 ` [patch 03/10] [PATCH] af_iucv: release reference to HS device frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 05/10] [PATCH] af_iucv: get rid of state IUCV_SEVERED frank.blaschka
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 604-af_iucv-rm-timer.diff --]
[-- Type: text/plain, Size: 1910 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

af_iucv contains timer infrastructure which is not exploited.
This patch removes the timer related code parts.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 include/net/iucv/af_iucv.h |    1 -
 net/iucv/af_iucv.c         |   22 ----------------------
 2 files changed, 23 deletions(-)

--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -146,7 +146,6 @@ unsigned int iucv_sock_poll(struct file
 			    poll_table *wait);
 void iucv_sock_link(struct iucv_sock_list *l, struct sock *s);
 void iucv_sock_unlink(struct iucv_sock_list *l, struct sock *s);
-int  iucv_sock_wait_cnt(struct sock *sk, unsigned long timeo);
 void iucv_accept_enqueue(struct sock *parent, struct sock *sk);
 void iucv_accept_unlink(struct sock *sk);
 struct sock *iucv_accept_dequeue(struct sock *parent, struct socket *newsock);
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -406,25 +406,6 @@ static int afiucv_hs_send(struct iucv_me
 	return err;
 }
 
-/* Timers */
-static void iucv_sock_timeout(unsigned long arg)
-{
-	struct sock *sk = (struct sock *)arg;
-
-	bh_lock_sock(sk);
-	sk->sk_err = ETIMEDOUT;
-	sk->sk_state_change(sk);
-	bh_unlock_sock(sk);
-
-	iucv_sock_kill(sk);
-	sock_put(sk);
-}
-
-static void iucv_sock_clear_timer(struct sock *sk)
-{
-	sk_stop_timer(sk, &sk->sk_timer);
-}
-
 static struct sock *__iucv_get_sock_by_name(char *nm)
 {
 	struct sock *sk;
@@ -477,7 +458,6 @@ static void iucv_sock_close(struct sock
 	int err, blen;
 	struct sk_buff *skb;
 
-	iucv_sock_clear_timer(sk);
 	lock_sock(sk);
 
 	switch (sk->sk_state) {
@@ -589,8 +569,6 @@ static struct sock *iucv_sock_alloc(stru
 	sk->sk_protocol = proto;
 	sk->sk_state	= IUCV_OPEN;
 
-	setup_timer(&sk->sk_timer, iucv_sock_timeout, (unsigned long)sk);
-
 	iucv_sock_link(&iucv_sk_list, sk);
 	return sk;
 }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 05/10] [PATCH] af_iucv: get rid of state IUCV_SEVERED
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (3 preceding siblings ...)
  2011-12-20  8:56 ` [patch 04/10] [PATCH] af_iucv: remove unused timer infrastructure frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 06/10] [PATCH] qeth: suspicious rcu_dereference_check in recovery frank.blaschka
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 605-af_iucv-rm-iucv-severed.diff --]
[-- Type: text/plain, Size: 3954 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

af_iucv differs unnecessarily between state IUCV_SEVERED and
IUCV_DISCONN. This patch removes state IUCV_SEVERED.
While simplifying af_iucv, this patch removes the 2nd invocation of
cpcmd as well.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 include/net/iucv/af_iucv.h |    1 -
 net/iucv/af_iucv.c         |   35 ++++++++---------------------------
 2 files changed, 8 insertions(+), 28 deletions(-)

--- a/include/net/iucv/af_iucv.h
+++ b/include/net/iucv/af_iucv.h
@@ -27,7 +27,6 @@ enum {
 	IUCV_OPEN,
 	IUCV_BOUND,
 	IUCV_LISTEN,
-	IUCV_SEVERED,
 	IUCV_DISCONN,
 	IUCV_CLOSING,
 	IUCV_CLOSED
--- a/net/iucv/af_iucv.c
+++ b/net/iucv/af_iucv.c
@@ -178,7 +178,6 @@ static int afiucv_pm_freeze(struct devic
 		iucv_skb_queue_purge(&iucv->send_skb_q);
 		skb_queue_purge(&iucv->backlog_skb_q);
 		switch (sk->sk_state) {
-		case IUCV_SEVERED:
 		case IUCV_DISCONN:
 		case IUCV_CLOSING:
 		case IUCV_CONNECTED:
@@ -223,7 +222,6 @@ static int afiucv_pm_restore_thaw(struct
 			sk->sk_state_change(sk);
 			break;
 		case IUCV_DISCONN:
-		case IUCV_SEVERED:
 		case IUCV_CLOSING:
 		case IUCV_LISTEN:
 		case IUCV_BOUND:
@@ -661,16 +659,12 @@ struct sock *iucv_accept_dequeue(struct
 		}
 
 		if (sk->sk_state == IUCV_CONNECTED ||
-		    sk->sk_state == IUCV_SEVERED ||
-		    sk->sk_state == IUCV_DISCONN ||	/* due to PM restore */
+		    sk->sk_state == IUCV_DISCONN ||
 		    !newsock) {
 			iucv_accept_unlink(sk);
 			if (newsock)
 				sock_graft(sk, newsock);
 
-			if (sk->sk_state == IUCV_SEVERED)
-				sk->sk_state = IUCV_DISCONN;
-
 			release_sock(sk);
 			return sk;
 		}
@@ -760,16 +754,13 @@ done:
 static int iucv_sock_autobind(struct sock *sk)
 {
 	struct iucv_sock *iucv = iucv_sk(sk);
-	char query_buffer[80];
 	char name[12];
 	int err = 0;
 
-	/* Set the userid and name */
-	cpcmd("QUERY USERID", query_buffer, sizeof(query_buffer), &err);
-	if (unlikely(err))
+	if (unlikely(!pr_iucv))
 		return -EPROTO;
 
-	memcpy(iucv->src_user_id, query_buffer, 8);
+	memcpy(iucv->src_user_id, iucv_userid, 8);
 
 	write_lock_bh(&iucv_sk_list.lock);
 
@@ -1345,7 +1336,7 @@ static int iucv_sock_recvmsg(struct kioc
 	int blen;
 	int err = 0;
 
-	if ((sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED) &&
+	if ((sk->sk_state == IUCV_DISCONN) &&
 	    skb_queue_empty(&iucv->backlog_skb_q) &&
 	    skb_queue_empty(&sk->sk_receive_queue) &&
 	    list_empty(&iucv->message_q.list))
@@ -1492,7 +1483,7 @@ unsigned int iucv_sock_poll(struct file
 	if (sk->sk_state == IUCV_CLOSED)
 		mask |= POLLHUP;
 
-	if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_SEVERED)
+	if (sk->sk_state == IUCV_DISCONN)
 		mask |= POLLIN;
 
 	if (sock_writeable(sk))
@@ -1519,7 +1510,6 @@ static int iucv_sock_shutdown(struct soc
 	switch (sk->sk_state) {
 	case IUCV_DISCONN:
 	case IUCV_CLOSING:
-	case IUCV_SEVERED:
 	case IUCV_CLOSED:
 		err = -ENOTCONN;
 		goto fail;
@@ -1874,10 +1864,7 @@ static void iucv_callback_connrej(struct
 {
 	struct sock *sk = path->private;
 
-	if (!list_empty(&iucv_sk(sk)->accept_q))
-		sk->sk_state = IUCV_SEVERED;
-	else
-		sk->sk_state = IUCV_DISCONN;
+	sk->sk_state = IUCV_DISCONN;
 
 	sk->sk_state_change(sk);
 }
@@ -2037,10 +2024,7 @@ static int afiucv_hs_callback_fin(struct
 	/* other end of connection closed */
 	if (iucv) {
 		bh_lock_sock(sk);
-		if (!list_empty(&iucv->accept_q))
-			sk->sk_state = IUCV_SEVERED;
-		else
-			sk->sk_state = IUCV_DISCONN;
+		sk->sk_state = IUCV_DISCONN;
 		sk->sk_state_change(sk);
 		bh_unlock_sock(sk);
 	}
@@ -2269,10 +2253,7 @@ static void afiucv_hs_callback_txnotify(
 				__skb_unlink(this, list);
 				dev_put(this->dev);
 				kfree_skb(this);
-				if (!list_empty(&iucv->accept_q))
-					sk->sk_state = IUCV_SEVERED;
-				else
-					sk->sk_state = IUCV_DISCONN;
+				sk->sk_state = IUCV_DISCONN;
 				sk->sk_state_change(sk);
 				break;
 			}

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 06/10] [PATCH] qeth: suspicious rcu_dereference_check in recovery
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (4 preceding siblings ...)
  2011-12-20  8:56 ` [patch 05/10] [PATCH] af_iucv: get rid of state IUCV_SEVERED frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 07/10] [PATCH] qeth: forbid recovery during shutdown frank.blaschka
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 606-qeth-rtnl-lock.diff --]
[-- Type: text/plain, Size: 2297 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

qeth layer3 recovery invokes its set_multicast_list function, which
invokes function __vlan_find_dev_deep requiring rcu_read_lock or
rtnl lock. This causes kernel messages:

kernel: [ INFO: suspicious rcu_dereference_check() usage. ]
kernel: ---------------------------------------------------
kernel: net/8021q/vlan_core.c:70 invoked rcu_dereference_check() without protection!

kernel: stack backtrace:
kernel: CPU: 0 Not tainted 3.1.0 #9
kernel: Process qeth_recover (pid: 2078, task: 000000007e584680, ksp: 000000007e3e3930)
kernel: 000000007e3e3d08 000000007e3e3c88 0000000000000002 0000000000000000 
kernel:       000000007e3e3d28 000000007e3e3ca0 000000007e3e3ca0 00000000005e77ce 
kernel:       0000000000000000 0000000000000001 ffffffffffffffff 0000000000000001 
kernel:       000000000000000d 000000000000000c 000000007e3e3cf0 0000000000000000 
kernel:       0000000000000000 0000000000100a18 000000007e3e3c88 000000007e3e3cc8 
kernel: Call Trace:
kernel: ([<0000000000100926>] show_trace+0xee/0x144)
kernel: [<00000000005d395c>] __vlan_find_dev_deep+0xb0/0x108
kernel: [<00000000004acd3a>] qeth_l3_set_multicast_list+0x976/0xe38
kernel: [<00000000004ae0f4>] __qeth_l3_set_online+0x75c/0x1498
kernel: [<00000000004aefec>] qeth_l3_recover+0xc4/0x1d0
kernel: [<0000000000185372>] kthread+0xa6/0xb0
kernel: [<00000000005ed4c6>] kernel_thread_starter+0x6/0xc
kernel: [<00000000005ed4c0>] kernel_thread_starter+0x0/0xc

The patch makes sure the rtnl lock is held once qeth recovery invokes
its set_multicast_list function.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 drivers/s390/net/qeth_l3_main.c |    7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3492,14 +3492,13 @@ contin:
 	else
 		netif_carrier_off(card->dev);
 	if (recover_flag == CARD_STATE_RECOVER) {
+		rtnl_lock();
 		if (recovery_mode)
 			__qeth_l3_open(card->dev);
-		else {
-			rtnl_lock();
+		else
 			dev_open(card->dev);
-			rtnl_unlock();
-		}
 		qeth_l3_set_multicast_list(card->dev);
+		rtnl_unlock();
 	}
 	/* let user_space know that device is online */
 	kobject_uevent(&gdev->dev.kobj, KOBJ_CHANGE);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 07/10] [PATCH] qeth: forbid recovery during shutdown
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (5 preceding siblings ...)
  2011-12-20  8:56 ` [patch 06/10] [PATCH] qeth: suspicious rcu_dereference_check in recovery frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 08/10] [PATCH] netiucv: allow multiple interfaces to same peer frank.blaschka
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 607-qeth-recovery-shutdown.diff --]
[-- Type: text/plain, Size: 3459 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

A recovery does not make sense during shutdown and may even cause an
error like this:

qeth 0.0.f503: A recovery process has been started for the device
Badness at drivers/s390/cio/qdio_main.c:1156
Modules linked in: autofs4 sunrpc dm_multipath scsi_dh scsi_mod qeth_l3 ipv6 vmu
r qeth qdio ccwgroup ext3 jbd mbcache dasd_eckd_mod dasd_mod dm_mirror dm_region
_hash dm_log dm_mod [last unloaded: scsi_wait_scan]
CPU: 3 Not tainted 2.6.32-202.el6.s390x #1
Process qeth_recover (pid: 1498, task: 000000003efe2040, ksp: 000000003d5e3b80)
Krnl PSW : 0404200180000000 000003c000be6da8 (qdio_int_handler+0x88/0x43c [qdio]
)
           R:0 T:1 IO:0 EX:0 Key:0 M:1 W:0 P:0 AS:0 CC:2 PM:0 EA:3
Krnl GPRS: ffffffffffff3bac 0000000000000005 0000000000000000 fffffffffffffff4
           0000000000000000 000000000000000c 0000000000000000 000000003ca97000
           0000000000000380 fffffffffffffff4 000000003f22d800 000000003f22c478
           000003c000bdf000 000003c000bea270 000000003f447e10 000000003f447db0
Krnl Code: 000003c000be6d9a: c21f00000004       clfi    %r1,4
           000003c000be6da0: a7c40021           brc     12,3c000be6de2
           000003c000be6da4: a7f40001           brc     15,3c000be6da6
          >000003c000be6da8: e320a0080004       lg      %r2,8(%r10)
           000003c000be6dae: a7390003           lghi    %r3,3
           000003c000be6db2: a72b0178           aghi    %r2,376
           000003c000be6db6: a7490001           lghi    %r4,1
           000003c000be6dba: a7590000           lghi    %r5,0
Call Trace:
([<000000000080ee80>] __per_cpu_offset+0x0/0x200)
[<00000000003d90e8>] ccw_device_call_handler+0x70/0xcc
[<00000000003d83a2>] ccw_device_irq+0x82/0x180
[<00000000003cc6a8>] do_IRQ+0x16c/0x1ec
[<0000000000118abe>] io_return+0x0/0x8
[<000003c000d04c74>] qeth_determine_capabilities+0x208/0x5cc [qeth]
([<000003c000d04c4a>] qeth_determine_capabilities+0x1de/0x5cc [qeth])
[<000003c000d0a6e0>] qeth_core_hardsetup_card+0x160/0x1258 [qeth]
[<000003c000f49f56>] __qeth_l3_set_online+0x132/0xb14 [qeth_l3]
[<000003c000f4ac70>] qeth_l3_recover+0x168/0x224 [qeth_l3]
[<000000000016e210>] kthread+0xa4/0xac
[<0000000000109c6e>] kernel_thread_starter+0x6/0xc
[<0000000000109c68>] kernel_thread_starter+0x0/0xc

The patch forbids start of a recovery once qeth shutdown is running.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 drivers/s390/net/qeth_l2_main.c |    1 +
 drivers/s390/net/qeth_l3_main.c |    1 +
 2 files changed, 2 insertions(+)

--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -1173,6 +1173,7 @@ static void __exit qeth_l2_exit(void)
 static void qeth_l2_shutdown(struct ccwgroup_device *gdev)
 {
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+	qeth_set_allowed_threads(card, 0, 1);
 	if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
 		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
 	qeth_qdio_clear_card(card, 0);
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3598,6 +3598,7 @@ static int qeth_l3_recover(void *ptr)
 static void qeth_l3_shutdown(struct ccwgroup_device *gdev)
 {
 	struct qeth_card *card = dev_get_drvdata(&gdev->dev);
+	qeth_set_allowed_threads(card, 0, 1);
 	if ((gdev->state == CCWGROUP_ONLINE) && card->info.hwtrap)
 		qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
 	qeth_qdio_clear_card(card, 0);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 08/10] [PATCH] netiucv: allow multiple interfaces to same peer
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (6 preceding siblings ...)
  2011-12-20  8:56 ` [patch 07/10] [PATCH] qeth: forbid recovery during shutdown frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 09/10] [PATCH] qeth: improve recovery during resource shortage frank.blaschka
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Ursula Braun

[-- Attachment #1: 608-netiucv-multi-if-peer.diff --]
[-- Type: text/plain, Size: 15365 bytes --]

From: Ursula Braun <ursula.braun@de.ibm.com>

The NETIUCV device driver allows to connect a Linux guest on z/VM to
another z/VM guest based on the z/VM communication facility IUCV.
Multiple output paths to different guests are possible, as well as
multiple input paths from different guests.
With this feature, you can configure multiple point-to-point NETIUCV
interfaces between your Linux on System z instance and another z/VM
guest.

Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 drivers/s390/net/netiucv.c |  217 +++++++++++++++++++++++++++------------------
 1 file changed, 135 insertions(+), 82 deletions(-)

--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -63,6 +63,7 @@
 
 #include <asm/io.h>
 #include <asm/uaccess.h>
+#include <asm/ebcdic.h>
 
 #include <net/iucv/iucv.h>
 #include "fsm.h"
@@ -75,7 +76,7 @@ MODULE_DESCRIPTION ("Linux for S/390 IUC
  * Debug Facility stuff
  */
 #define IUCV_DBF_SETUP_NAME "iucv_setup"
-#define IUCV_DBF_SETUP_LEN 32
+#define IUCV_DBF_SETUP_LEN 64
 #define IUCV_DBF_SETUP_PAGES 2
 #define IUCV_DBF_SETUP_NR_AREAS 1
 #define IUCV_DBF_SETUP_LEVEL 3
@@ -226,6 +227,7 @@ struct iucv_connection {
 	struct net_device         *netdev;
 	struct connection_profile prof;
 	char                      userid[9];
+	char			  userdata[17];
 };
 
 /**
@@ -263,7 +265,7 @@ struct ll_header {
 };
 
 #define NETIUCV_HDRLEN		 (sizeof(struct ll_header))
-#define NETIUCV_BUFSIZE_MAX      32768
+#define NETIUCV_BUFSIZE_MAX	 65537
 #define NETIUCV_BUFSIZE_DEFAULT  NETIUCV_BUFSIZE_MAX
 #define NETIUCV_MTU_MAX          (NETIUCV_BUFSIZE_MAX - NETIUCV_HDRLEN)
 #define NETIUCV_MTU_DEFAULT      9216
@@ -288,7 +290,12 @@ static inline int netiucv_test_and_set_b
 	return test_and_set_bit(0, &priv->tbusy);
 }
 
-static u8 iucvMagic[16] = {
+static u8 iucvMagic_ascii[16] = {
+	0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+	0x30, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20
+};
+
+static u8 iucvMagic_ebcdic[16] = {
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
 	0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
 };
@@ -301,18 +308,38 @@ static u8 iucvMagic[16] = {
  *
  * @returns The printable string (static data!!)
  */
-static char *netiucv_printname(char *name)
+static char *netiucv_printname(char *name, int len)
 {
-	static char tmp[9];
+	static char tmp[17];
 	char *p = tmp;
-	memcpy(tmp, name, 8);
-	tmp[8] = '\0';
-	while (*p && (!isspace(*p)))
+	memcpy(tmp, name, len);
+	tmp[len] = '\0';
+	while (*p && ((p - tmp) < len) && (!isspace(*p)))
 		p++;
 	*p = '\0';
 	return tmp;
 }
 
+static char *netiucv_printuser(struct iucv_connection *conn)
+{
+	static char tmp_uid[9];
+	static char tmp_udat[17];
+	static char buf[100];
+
+	if (memcmp(conn->userdata, iucvMagic_ebcdic, 16)) {
+		tmp_uid[8] = '\0';
+		tmp_udat[16] = '\0';
+		memcpy(tmp_uid, conn->userid, 8);
+		memcpy(tmp_uid, netiucv_printname(tmp_uid, 8), 8);
+		memcpy(tmp_udat, conn->userdata, 16);
+		EBCASC(tmp_udat, 16);
+		memcpy(tmp_udat, netiucv_printname(tmp_udat, 16), 16);
+		sprintf(buf, "%s.%s", tmp_uid, tmp_udat);
+		return buf;
+	} else
+		return netiucv_printname(conn->userid, 8);
+}
+
 /**
  * States of the interface statemachine.
  */
@@ -563,15 +590,18 @@ static int netiucv_callback_connreq(stru
 {
 	struct iucv_connection *conn = path->private;
 	struct iucv_event ev;
+	static char tmp_user[9];
+	static char tmp_udat[17];
 	int rc;
 
-	if (memcmp(iucvMagic, ipuser, 16))
-		/* ipuser must match iucvMagic. */
-		return -EINVAL;
 	rc = -EINVAL;
+	memcpy(tmp_user, netiucv_printname(ipvmid, 8), 8);
+	memcpy(tmp_udat, ipuser, 16);
+	EBCASC(tmp_udat, 16);
 	read_lock_bh(&iucv_connection_rwlock);
 	list_for_each_entry(conn, &iucv_connection_list, list) {
-		if (strncmp(ipvmid, conn->userid, 8))
+		if (strncmp(ipvmid, conn->userid, 8) ||
+		    strncmp(ipuser, conn->userdata, 16))
 			continue;
 		/* Found a matching connection for this path. */
 		conn->path = path;
@@ -580,6 +610,8 @@ static int netiucv_callback_connreq(stru
 		fsm_event(conn->fsm, CONN_EVENT_CONN_REQ, &ev);
 		rc = 0;
 	}
+	IUCV_DBF_TEXT_(setup, 2, "Connection requested for %s.%s\n",
+		       tmp_user, netiucv_printname(tmp_udat, 16));
 	read_unlock_bh(&iucv_connection_rwlock);
 	return rc;
 }
@@ -816,7 +848,7 @@ static void conn_action_connaccept(fsm_i
 	conn->path = path;
 	path->msglim = NETIUCV_QUEUELEN_DEFAULT;
 	path->flags = 0;
-	rc = iucv_path_accept(path, &netiucv_handler, NULL, conn);
+	rc = iucv_path_accept(path, &netiucv_handler, conn->userdata , conn);
 	if (rc) {
 		IUCV_DBF_TEXT_(setup, 2, "rc %d from iucv_accept", rc);
 		return;
@@ -854,7 +886,7 @@ static void conn_action_conntimsev(fsm_i
 
 	IUCV_DBF_TEXT(trace, 3, __func__);
 	fsm_deltimer(&conn->timer);
-	iucv_path_sever(conn->path, NULL);
+	iucv_path_sever(conn->path, conn->userdata);
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
 }
 
@@ -867,9 +899,9 @@ static void conn_action_connsever(fsm_in
 	IUCV_DBF_TEXT(trace, 3, __func__);
 
 	fsm_deltimer(&conn->timer);
-	iucv_path_sever(conn->path, NULL);
-	dev_info(privptr->dev, "The peer interface of the IUCV device"
-		" has closed the connection\n");
+	iucv_path_sever(conn->path, conn->userdata);
+	dev_info(privptr->dev, "The peer z/VM guest %s has closed the "
+			       "connection\n", netiucv_printuser(conn));
 	IUCV_DBF_TEXT(data, 2,
 		      "conn_action_connsever: Remote dropped connection\n");
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
@@ -886,8 +918,6 @@ static void conn_action_start(fsm_instan
 	IUCV_DBF_TEXT(trace, 3, __func__);
 
 	fsm_newstate(fi, CONN_STATE_STARTWAIT);
-	IUCV_DBF_TEXT_(setup, 2, "%s('%s'): connecting ...\n",
-		netdev->name, conn->userid);
 
 	/*
 	 * We must set the state before calling iucv_connect because the
@@ -897,8 +927,11 @@ static void conn_action_start(fsm_instan
 
 	fsm_newstate(fi, CONN_STATE_SETUPWAIT);
 	conn->path = iucv_path_alloc(NETIUCV_QUEUELEN_DEFAULT, 0, GFP_KERNEL);
+	IUCV_DBF_TEXT_(setup, 2, "%s: connecting to %s ...\n",
+		netdev->name, netiucv_printuser(conn));
+
 	rc = iucv_path_connect(conn->path, &netiucv_handler, conn->userid,
-			       NULL, iucvMagic, conn);
+			       NULL, conn->userdata, conn);
 	switch (rc) {
 	case 0:
 		netdev->tx_queue_len = conn->path->msglim;
@@ -908,13 +941,13 @@ static void conn_action_start(fsm_instan
 	case 11:
 		dev_warn(privptr->dev,
 			"The IUCV device failed to connect to z/VM guest %s\n",
-			netiucv_printname(conn->userid));
+			netiucv_printname(conn->userid, 8));
 		fsm_newstate(fi, CONN_STATE_STARTWAIT);
 		break;
 	case 12:
 		dev_warn(privptr->dev,
 			"The IUCV device failed to connect to the peer on z/VM"
-			" guest %s\n", netiucv_printname(conn->userid));
+			" guest %s\n", netiucv_printname(conn->userid, 8));
 		fsm_newstate(fi, CONN_STATE_STARTWAIT);
 		break;
 	case 13:
@@ -927,7 +960,7 @@ static void conn_action_start(fsm_instan
 		dev_err(privptr->dev,
 			"z/VM guest %s has too many IUCV connections"
 			" to connect with the IUCV device\n",
-			netiucv_printname(conn->userid));
+			netiucv_printname(conn->userid, 8));
 		fsm_newstate(fi, CONN_STATE_CONNERR);
 		break;
 	case 15:
@@ -972,7 +1005,7 @@ static void conn_action_stop(fsm_instanc
 	netiucv_purge_skb_queue(&conn->collect_queue);
 	if (conn->path) {
 		IUCV_DBF_TEXT(trace, 5, "calling iucv_path_sever\n");
-		iucv_path_sever(conn->path, iucvMagic);
+		iucv_path_sever(conn->path, conn->userdata);
 		kfree(conn->path);
 		conn->path = NULL;
 	}
@@ -1090,7 +1123,8 @@ dev_action_connup(fsm_instance *fi, int
 			fsm_newstate(fi, DEV_STATE_RUNNING);
 			dev_info(privptr->dev,
 				"The IUCV device has been connected"
-				" successfully to %s\n", privptr->conn->userid);
+				" successfully to %s\n",
+				netiucv_printuser(privptr->conn));
 			IUCV_DBF_TEXT(setup, 3,
 				"connection is up and running\n");
 			break;
@@ -1452,45 +1486,72 @@ static ssize_t user_show(struct device *
 	struct netiucv_priv *priv = dev_get_drvdata(dev);
 
 	IUCV_DBF_TEXT(trace, 5, __func__);
-	return sprintf(buf, "%s\n", netiucv_printname(priv->conn->userid));
+	return sprintf(buf, "%s\n", netiucv_printuser(priv->conn));
 }
 
-static ssize_t user_write(struct device *dev, struct device_attribute *attr,
-			  const char *buf, size_t count)
+static int netiucv_check_user(const char *buf, size_t count, char *username,
+			      char *userdata)
 {
-	struct netiucv_priv *priv = dev_get_drvdata(dev);
-	struct net_device *ndev = priv->conn->netdev;
-	char    *p;
-	char    *tmp;
-	char 	username[9];
-	int 	i;
-	struct iucv_connection *cp;
+	const char *p;
+	int i;
 
-	IUCV_DBF_TEXT(trace, 3, __func__);
-	if (count > 9) {
-		IUCV_DBF_TEXT_(setup, 2,
-			       "%d is length of username\n", (int) count);
+	p = strchr(buf, '.');
+	if ((p && ((count > 26) ||
+		   ((p - buf) > 8) ||
+		   (buf + count - p > 18))) ||
+	    (!p && (count > 9))) {
+		IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");
 		return -EINVAL;
 	}
 
-	tmp = strsep((char **) &buf, "\n");
-	for (i = 0, p = tmp; i < 8 && *p; i++, p++) {
-		if (isalnum(*p) || (*p == '$')) {
-			username[i]= toupper(*p);
+	for (i = 0, p = buf; i < 8 && *p && *p != '.'; i++, p++) {
+		if (isalnum(*p) || *p == '$') {
+			username[i] = toupper(*p);
 			continue;
 		}
-		if (*p == '\n') {
+		if (*p == '\n')
 			/* trailing lf, grr */
 			break;
-		}
 		IUCV_DBF_TEXT_(setup, 2,
-			       "username: invalid character %c\n", *p);
+			       "conn_write: invalid character %02x\n", *p);
 		return -EINVAL;
 	}
 	while (i < 8)
 		username[i++] = ' ';
 	username[8] = '\0';
 
+	if (*p == '.') {
+		p++;
+		for (i = 0; i < 16 && *p; i++, p++) {
+			if (*p == '\n')
+				break;
+			userdata[i] = toupper(*p);
+		}
+		while (i > 0 && i < 16)
+			userdata[i++] = ' ';
+	} else
+		memcpy(userdata, iucvMagic_ascii, 16);
+	userdata[16] = '\0';
+	ASCEBC(userdata, 16);
+
+	return 0;
+}
+
+static ssize_t user_write(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct netiucv_priv *priv = dev_get_drvdata(dev);
+	struct net_device *ndev = priv->conn->netdev;
+	char	username[9];
+	char	userdata[17];
+	int	rc;
+	struct iucv_connection *cp;
+
+	IUCV_DBF_TEXT(trace, 3, __func__);
+	rc = netiucv_check_user(buf, count, username, userdata);
+	if (rc)
+		return rc;
+
 	if (memcmp(username, priv->conn->userid, 9) &&
 	    (ndev->flags & (IFF_UP | IFF_RUNNING))) {
 		/* username changed while the interface is active. */
@@ -1499,15 +1560,17 @@ static ssize_t user_write(struct device
 	}
 	read_lock_bh(&iucv_connection_rwlock);
 	list_for_each_entry(cp, &iucv_connection_list, list) {
-		if (!strncmp(username, cp->userid, 9) && cp->netdev != ndev) {
+		if (!strncmp(username, cp->userid, 9) &&
+		   !strncmp(userdata, cp->userdata, 17) && cp->netdev != ndev) {
 			read_unlock_bh(&iucv_connection_rwlock);
-			IUCV_DBF_TEXT_(setup, 2, "user_write: Connection "
-				"to %s already exists\n", username);
+			IUCV_DBF_TEXT_(setup, 2, "user_write: Connection to %s "
+				"already exists\n", netiucv_printuser(cp));
 			return -EEXIST;
 		}
 	}
 	read_unlock_bh(&iucv_connection_rwlock);
 	memcpy(priv->conn->userid, username, 9);
+	memcpy(priv->conn->userdata, userdata, 17);
 	return count;
 }
 
@@ -1537,7 +1600,8 @@ static ssize_t buffer_write (struct devi
 	bs1 = simple_strtoul(buf, &e, 0);
 
 	if (e && (!isspace(*e))) {
-		IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %c\n", *e);
+		IUCV_DBF_TEXT_(setup, 2, "buffer_write: invalid char %02x\n",
+			*e);
 		return -EINVAL;
 	}
 	if (bs1 > NETIUCV_BUFSIZE_MAX) {
@@ -1864,7 +1928,8 @@ static void netiucv_unregister_device(st
  * Add it to the list of netiucv connections;
  */
 static struct iucv_connection *netiucv_new_connection(struct net_device *dev,
-						      char *username)
+						      char *username,
+						      char *userdata)
 {
 	struct iucv_connection *conn;
 
@@ -1893,6 +1958,8 @@ static struct iucv_connection *netiucv_n
 	fsm_settimer(conn->fsm, &conn->timer);
 	fsm_newstate(conn->fsm, CONN_STATE_INVALID);
 
+	if (userdata)
+		memcpy(conn->userdata, userdata, 17);
 	if (username) {
 		memcpy(conn->userid, username, 9);
 		fsm_newstate(conn->fsm, CONN_STATE_STOPPED);
@@ -1919,6 +1986,7 @@ out:
  */
 static void netiucv_remove_connection(struct iucv_connection *conn)
 {
+
 	IUCV_DBF_TEXT(trace, 3, __func__);
 	write_lock_bh(&iucv_connection_rwlock);
 	list_del_init(&conn->list);
@@ -1926,7 +1994,7 @@ static void netiucv_remove_connection(st
 	fsm_deltimer(&conn->timer);
 	netiucv_purge_skb_queue(&conn->collect_queue);
 	if (conn->path) {
-		iucv_path_sever(conn->path, iucvMagic);
+		iucv_path_sever(conn->path, conn->userdata);
 		kfree(conn->path);
 		conn->path = NULL;
 	}
@@ -1985,7 +2053,7 @@ static void netiucv_setup_netdevice(stru
 /**
  * Allocate and initialize everything of a net device.
  */
-static struct net_device *netiucv_init_netdevice(char *username)
+static struct net_device *netiucv_init_netdevice(char *username, char *userdata)
 {
 	struct netiucv_priv *privptr;
 	struct net_device *dev;
@@ -2004,7 +2072,7 @@ static struct net_device *netiucv_init_n
 	if (!privptr->fsm)
 		goto out_netdev;
 
-	privptr->conn = netiucv_new_connection(dev, username);
+	privptr->conn = netiucv_new_connection(dev, username, userdata);
 	if (!privptr->conn) {
 		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_new_connection\n");
 		goto out_fsm;
@@ -2022,47 +2090,31 @@ out_netdev:
 static ssize_t conn_write(struct device_driver *drv,
 			  const char *buf, size_t count)
 {
-	const char *p;
 	char username[9];
-	int i, rc;
+	char userdata[17];
+	int rc;
 	struct net_device *dev;
 	struct netiucv_priv *priv;
 	struct iucv_connection *cp;
 
 	IUCV_DBF_TEXT(trace, 3, __func__);
-	if (count>9) {
-		IUCV_DBF_TEXT(setup, 2, "conn_write: too long\n");
-		return -EINVAL;
-	}
-
-	for (i = 0, p = buf; i < 8 && *p; i++, p++) {
-		if (isalnum(*p) || *p == '$') {
-			username[i] = toupper(*p);
-			continue;
-		}
-		if (*p == '\n')
-			/* trailing lf, grr */
-			break;
-		IUCV_DBF_TEXT_(setup, 2,
-			       "conn_write: invalid character %c\n", *p);
-		return -EINVAL;
-	}
-	while (i < 8)
-		username[i++] = ' ';
-	username[8] = '\0';
+	rc = netiucv_check_user(buf, count, username, userdata);
+	if (rc)
+		return rc;
 
 	read_lock_bh(&iucv_connection_rwlock);
 	list_for_each_entry(cp, &iucv_connection_list, list) {
-		if (!strncmp(username, cp->userid, 9)) {
+		if (!strncmp(username, cp->userid, 9) &&
+		    !strncmp(userdata, cp->userdata, 17)) {
 			read_unlock_bh(&iucv_connection_rwlock);
-			IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection "
-				"to %s already exists\n", username);
+			IUCV_DBF_TEXT_(setup, 2, "conn_write: Connection to %s "
+				"already exists\n", netiucv_printuser(cp));
 			return -EEXIST;
 		}
 	}
 	read_unlock_bh(&iucv_connection_rwlock);
 
-	dev = netiucv_init_netdevice(username);
+	dev = netiucv_init_netdevice(username, userdata);
 	if (!dev) {
 		IUCV_DBF_TEXT(setup, 2, "NULL from netiucv_init_netdevice\n");
 		return -ENODEV;
@@ -2083,8 +2135,9 @@ static ssize_t conn_write(struct device_
 	if (rc)
 		goto out_unreg;
 
-	dev_info(priv->dev, "The IUCV interface to %s has been"
-		" established successfully\n", netiucv_printname(username));
+	dev_info(priv->dev, "The IUCV interface to %s has been established "
+			    "successfully\n",
+		netiucv_printuser(priv->conn));
 
 	return count;
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 09/10] [PATCH] qeth: improve recovery during resource shortage
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (7 preceding siblings ...)
  2011-12-20  8:56 ` [patch 08/10] [PATCH] netiucv: allow multiple interfaces to same peer frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20  8:56 ` [patch 10/10] [PATCH] qeth: recovery through asynchronous delivery frank.blaschka
  2011-12-20 19:05 ` [patch 00/10] s390: network driver features and fixes for net-next David Miller
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390

[-- Attachment #1: 610-qeth-resource-shortage.diff --]
[-- Type: text/plain, Size: 1372 bytes --]

From: Frank Blaschka <frank.blaschka@de.ibm.com>

In case there are no system resources to run a recovery we have to clear
recovery bitmasks so a further automatic or manual driven recovery can
fix up the device.

Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 drivers/s390/net/qeth_core_main.c |   11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -1329,6 +1329,7 @@ static int qeth_do_start_thread(struct q
 
 static void qeth_start_kernel_thread(struct work_struct *work)
 {
+	struct task_struct *ts;
 	struct qeth_card *card = container_of(work, struct qeth_card,
 					kernel_thread_starter);
 	QETH_CARD_TEXT(card , 2, "strthrd");
@@ -1336,9 +1337,15 @@ static void qeth_start_kernel_thread(str
 	if (card->read.state != CH_STATE_UP &&
 	    card->write.state != CH_STATE_UP)
 		return;
-	if (qeth_do_start_thread(card, QETH_RECOVER_THREAD))
-		kthread_run(card->discipline.recover, (void *) card,
+	if (qeth_do_start_thread(card, QETH_RECOVER_THREAD)) {
+		ts = kthread_run(card->discipline.recover, (void *)card,
 				"qeth_recover");
+		if (IS_ERR(ts)) {
+			qeth_clear_thread_start_bit(card, QETH_RECOVER_THREAD);
+			qeth_clear_thread_running_bit(card,
+				QETH_RECOVER_THREAD);
+		}
+	}
 }
 
 static int qeth_setup_card(struct qeth_card *card)

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 10/10] [PATCH] qeth: recovery through asynchronous delivery
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (8 preceding siblings ...)
  2011-12-20  8:56 ` [patch 09/10] [PATCH] qeth: improve recovery during resource shortage frank.blaschka
@ 2011-12-20  8:56 ` frank.blaschka
  2011-12-20 19:05 ` [patch 00/10] s390: network driver features and fixes for net-next David Miller
  10 siblings, 0 replies; 12+ messages in thread
From: frank.blaschka @ 2011-12-20  8:56 UTC (permalink / raw)
  To: davem; +Cc: netdev, linux-s390, Einar Lueck, Ursula Braun

[-- Attachment #1: 611-qeth-async-recovery.diff --]
[-- Type: text/plain, Size: 4423 bytes --]

From: Einar Lueck <elelueck@de.ibm.com>

If recovery is triggered in presence of pending asynchronous
deliveries of storage blocks we do a forced cleanup after
the corresponding tasklets are completely stopped and trigger
appropriate notifications for the correspondingerror state.

Signed-off-by: Einar Lueck <elelueck@de.ibm.com>
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
---

 drivers/s390/net/qeth_core_main.c |   34 +++++++++++++++++++++++++++++-----
 drivers/s390/net/qeth_l3_main.c   |    5 +++++
 2 files changed, 34 insertions(+), 5 deletions(-)

--- a/drivers/s390/net/qeth_core_main.c
+++ b/drivers/s390/net/qeth_core_main.c
@@ -66,7 +66,7 @@ static void qeth_release_skbs(struct qet
 static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
 		struct qeth_qdio_out_buffer *buf,
 		enum qeth_qdio_buffer_states newbufstate);
-
+static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
 static inline const char *qeth_get_cardname(struct qeth_card *card)
 {
@@ -363,6 +363,9 @@ static inline enum iucv_tx_notify qeth_c
 static inline void qeth_cleanup_handled_pending(struct qeth_qdio_out_q *q,
 	int bidx, int forced_cleanup)
 {
+	if (q->card->options.cq != QETH_CQ_ENABLED)
+		return;
+
 	if (q->bufs[bidx]->next_pending != NULL) {
 		struct qeth_qdio_out_buffer *head = q->bufs[bidx];
 		struct qeth_qdio_out_buffer *c = q->bufs[bidx]->next_pending;
@@ -390,6 +393,13 @@ static inline void qeth_cleanup_handled_
 
 		}
 	}
+	if (forced_cleanup && (atomic_read(&(q->bufs[bidx]->state)) ==
+					QETH_QDIO_BUF_HANDLED_DELAYED)) {
+		/* for recovery situations */
+		q->bufs[bidx]->aob = q->bufstates[bidx].aob;
+		qeth_init_qdio_out_buf(q, bidx);
+		QETH_CARD_TEXT(q->card, 2, "clprecov");
+	}
 }
 
 
@@ -412,7 +422,6 @@ static inline void qeth_qdio_handle_aob(
 		notification = TX_NOTIFY_OK;
 	} else {
 		BUG_ON(atomic_read(&buffer->state) != QETH_QDIO_BUF_PENDING);
-
 		atomic_set(&buffer->state, QETH_QDIO_BUF_IN_CQ);
 		notification = TX_NOTIFY_DELAYED_OK;
 	}
@@ -425,7 +434,8 @@ static inline void qeth_qdio_handle_aob(
 
 	buffer->aob = NULL;
 	qeth_clear_output_buffer(buffer->q, buffer,
-				QETH_QDIO_BUF_HANDLED_DELAYED);
+				 QETH_QDIO_BUF_HANDLED_DELAYED);
+
 	/* from here on: do not touch buffer anymore */
 	qdio_release_aob(aob);
 }
@@ -1113,11 +1123,25 @@ out:
 static void qeth_release_skbs(struct qeth_qdio_out_buffer *buf)
 {
 	struct sk_buff *skb;
+	struct iucv_sock *iucv;
+	int notify_general_error = 0;
+
+	if (atomic_read(&buf->state) == QETH_QDIO_BUF_PENDING)
+		notify_general_error = 1;
+
+	/* release may never happen from within CQ tasklet scope */
+	BUG_ON(atomic_read(&buf->state) == QETH_QDIO_BUF_IN_CQ);
 
 	skb = skb_dequeue(&buf->skb_list);
 	while (skb) {
 		QETH_CARD_TEXT(buf->q->card, 5, "skbr");
 		QETH_CARD_TEXT_(buf->q->card, 5, "%lx", (long) skb);
+		if (notify_general_error && skb->protocol == ETH_P_AF_IUCV) {
+			if (skb->sk) {
+				iucv = iucv_sk(skb->sk);
+				iucv->sk_txnotify(skb, TX_NOTIFY_GENERALERROR);
+			}
+		}
 		atomic_dec(&skb->users);
 		dev_kfree_skb_any(skb);
 		skb = skb_dequeue(&buf->skb_list);
@@ -1160,7 +1184,7 @@ static void qeth_clear_outq_buffers(stru
 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j) {
 		if (!q->bufs[j])
 			continue;
-		qeth_cleanup_handled_pending(q, j, free);
+		qeth_cleanup_handled_pending(q, j, 1);
 		qeth_clear_output_buffer(q, q->bufs[j], QETH_QDIO_BUF_EMPTY);
 		if (free) {
 			kmem_cache_free(qeth_qdio_outbuf_cache, q->bufs[j]);
@@ -1207,7 +1231,7 @@ static void qeth_free_qdio_buffers(struc
 	qeth_free_cq(card);
 	cancel_delayed_work_sync(&card->buffer_reclaim_work);
 	for (j = 0; j < QDIO_MAX_BUFFERS_PER_Q; ++j)
-		kfree_skb(card->qdio.in_q->bufs[j].rx_skb);
+		dev_kfree_skb_any(card->qdio.in_q->bufs[j].rx_skb);
 	kfree(card->qdio.in_q);
 	card->qdio.in_q = NULL;
 	/* inbound buffer pool */
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -3544,6 +3544,11 @@ static int __qeth_l3_set_offline(struct
 		card->info.hwtrap = 1;
 	}
 	qeth_l3_stop_card(card, recovery_mode);
+	if ((card->options.cq == QETH_CQ_ENABLED) && card->dev) {
+		rtnl_lock();
+		call_netdevice_notifiers(NETDEV_REBOOT, card->dev);
+		rtnl_unlock();
+	}
 	rc  = ccw_device_set_offline(CARD_DDEV(card));
 	rc2 = ccw_device_set_offline(CARD_WDEV(card));
 	rc3 = ccw_device_set_offline(CARD_RDEV(card));

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [patch 00/10] s390: network driver features and fixes for net-next
  2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
                   ` (9 preceding siblings ...)
  2011-12-20  8:56 ` [patch 10/10] [PATCH] qeth: recovery through asynchronous delivery frank.blaschka
@ 2011-12-20 19:05 ` David Miller
  10 siblings, 0 replies; 12+ messages in thread
From: David Miller @ 2011-12-20 19:05 UTC (permalink / raw)
  To: frank.blaschka; +Cc: netdev, linux-s390

From: frank.blaschka@de.ibm.com
Date: Tue, 20 Dec 2011 09:56:26 +0100

> here are some s390 network driver features and fixes for net-next

Series applied, thanks.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-12-20 19:05 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-20  8:56 [patch 00/10] s390: network driver features and fixes for net-next frank.blaschka
2011-12-20  8:56 ` [patch 01/10] [PATCH] af_iucv: support ancillary data with HS transport frank.blaschka
2011-12-20  8:56 ` [patch 02/10] [PATCH] af_iucv: accelerate close for " frank.blaschka
2011-12-20  8:56 ` [patch 03/10] [PATCH] af_iucv: release reference to HS device frank.blaschka
2011-12-20  8:56 ` [patch 04/10] [PATCH] af_iucv: remove unused timer infrastructure frank.blaschka
2011-12-20  8:56 ` [patch 05/10] [PATCH] af_iucv: get rid of state IUCV_SEVERED frank.blaschka
2011-12-20  8:56 ` [patch 06/10] [PATCH] qeth: suspicious rcu_dereference_check in recovery frank.blaschka
2011-12-20  8:56 ` [patch 07/10] [PATCH] qeth: forbid recovery during shutdown frank.blaschka
2011-12-20  8:56 ` [patch 08/10] [PATCH] netiucv: allow multiple interfaces to same peer frank.blaschka
2011-12-20  8:56 ` [patch 09/10] [PATCH] qeth: improve recovery during resource shortage frank.blaschka
2011-12-20  8:56 ` [patch 10/10] [PATCH] qeth: recovery through asynchronous delivery frank.blaschka
2011-12-20 19:05 ` [patch 00/10] s390: network driver features and fixes for net-next David Miller

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).