diff options
| author | Ursula Braun <ursula.braun@de.ibm.com> | 2012-02-07 19:19:47 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-02-08 18:50:19 -0500 |
| commit | 800c5eb7b5eba6cb2a32738d763fd59f0fbcdde4 (patch) | |
| tree | 870a32bb186b395c7e70da55a1d1b17e37342336 | |
| parent | 7f1b0ea42a800713a3d56e1e8ca1a845e0461ca2 (diff) | |
af_iucv: change net_device handling for HS transport
This patch saves the net_device in the iucv_sock structure during
bind in order to fasten skb sending.
In addition some other small improvements are made for HS transport:
- error checking when sending skbs
- locking changes in afiucv_hs_callback_txnotify
- skb freeing in afiucv_hs_callback_txnotify
And finally it contains code cleanup to get rid of iucv_skb_queue_purge.
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
| -rw-r--r-- | include/net/iucv/af_iucv.h | 1 | ||||
| -rw-r--r-- | net/iucv/af_iucv.c | 119 |
2 files changed, 63 insertions, 57 deletions
diff --git a/include/net/iucv/af_iucv.h b/include/net/iucv/af_iucv.h index 0954ec95915..a1517887aea 100644 --- a/include/net/iucv/af_iucv.h +++ b/include/net/iucv/af_iucv.h | |||
| @@ -113,6 +113,7 @@ struct iucv_sock { | |||
| 113 | spinlock_t accept_q_lock; | 113 | spinlock_t accept_q_lock; |
| 114 | struct sock *parent; | 114 | struct sock *parent; |
| 115 | struct iucv_path *path; | 115 | struct iucv_path *path; |
| 116 | struct net_device *hs_dev; | ||
| 116 | struct sk_buff_head send_skb_q; | 117 | struct sk_buff_head send_skb_q; |
| 117 | struct sk_buff_head backlog_skb_q; | 118 | struct sk_buff_head backlog_skb_q; |
| 118 | struct sock_msg_q message_q; | 119 | struct sock_msg_q message_q; |
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index ef6ab71921f..fbce4a3126d 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -131,17 +131,6 @@ static inline void low_nmcpy(unsigned char *dst, char *src) | |||
| 131 | memcpy(&dst[8], src, 8); | 131 | memcpy(&dst[8], src, 8); |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static void iucv_skb_queue_purge(struct sk_buff_head *list) | ||
| 135 | { | ||
| 136 | struct sk_buff *skb; | ||
| 137 | |||
| 138 | while ((skb = skb_dequeue(list)) != NULL) { | ||
| 139 | if (skb->dev) | ||
| 140 | dev_put(skb->dev); | ||
| 141 | kfree_skb(skb); | ||
| 142 | } | ||
| 143 | } | ||
| 144 | |||
| 145 | static int afiucv_pm_prepare(struct device *dev) | 134 | static int afiucv_pm_prepare(struct device *dev) |
| 146 | { | 135 | { |
| 147 | #ifdef CONFIG_PM_DEBUG | 136 | #ifdef CONFIG_PM_DEBUG |
| @@ -176,7 +165,7 @@ static int afiucv_pm_freeze(struct device *dev) | |||
| 176 | read_lock(&iucv_sk_list.lock); | 165 | read_lock(&iucv_sk_list.lock); |
| 177 | sk_for_each(sk, node, &iucv_sk_list.head) { | 166 | sk_for_each(sk, node, &iucv_sk_list.head) { |
| 178 | iucv = iucv_sk(sk); | 167 | iucv = iucv_sk(sk); |
| 179 | iucv_skb_queue_purge(&iucv->send_skb_q); | 168 | skb_queue_purge(&iucv->send_skb_q); |
| 180 | skb_queue_purge(&iucv->backlog_skb_q); | 169 | skb_queue_purge(&iucv->backlog_skb_q); |
| 181 | switch (sk->sk_state) { | 170 | switch (sk->sk_state) { |
| 182 | case IUCV_DISCONN: | 171 | case IUCV_DISCONN: |
| @@ -337,7 +326,6 @@ static void iucv_sock_wake_msglim(struct sock *sk) | |||
| 337 | static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, | 326 | static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, |
| 338 | struct sk_buff *skb, u8 flags) | 327 | struct sk_buff *skb, u8 flags) |
| 339 | { | 328 | { |
| 340 | struct net *net = sock_net(sock); | ||
| 341 | struct iucv_sock *iucv = iucv_sk(sock); | 329 | struct iucv_sock *iucv = iucv_sk(sock); |
| 342 | struct af_iucv_trans_hdr *phs_hdr; | 330 | struct af_iucv_trans_hdr *phs_hdr; |
| 343 | struct sk_buff *nskb; | 331 | struct sk_buff *nskb; |
| @@ -374,10 +362,10 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, | |||
| 374 | if (imsg) | 362 | if (imsg) |
| 375 | memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); | 363 | memcpy(&phs_hdr->iucv_hdr, imsg, sizeof(struct iucv_message)); |
| 376 | 364 | ||
| 377 | skb->dev = dev_get_by_index(net, sock->sk_bound_dev_if); | 365 | skb->dev = iucv->hs_dev; |
| 378 | if (!skb->dev) | 366 | if (!skb->dev) |
| 379 | return -ENODEV; | 367 | return -ENODEV; |
| 380 | if (!(skb->dev->flags & IFF_UP)) | 368 | if (!(skb->dev->flags & IFF_UP) || !netif_carrier_ok(skb->dev)) |
| 381 | return -ENETDOWN; | 369 | return -ENETDOWN; |
| 382 | if (skb->len > skb->dev->mtu) { | 370 | if (skb->len > skb->dev->mtu) { |
| 383 | if (sock->sk_type == SOCK_SEQPACKET) | 371 | if (sock->sk_type == SOCK_SEQPACKET) |
| @@ -392,15 +380,14 @@ static int afiucv_hs_send(struct iucv_message *imsg, struct sock *sock, | |||
| 392 | return -ENOMEM; | 380 | return -ENOMEM; |
| 393 | skb_queue_tail(&iucv->send_skb_q, nskb); | 381 | skb_queue_tail(&iucv->send_skb_q, nskb); |
| 394 | err = dev_queue_xmit(skb); | 382 | err = dev_queue_xmit(skb); |
| 395 | if (err) { | 383 | if (net_xmit_eval(err)) { |
| 396 | skb_unlink(nskb, &iucv->send_skb_q); | 384 | skb_unlink(nskb, &iucv->send_skb_q); |
| 397 | dev_put(nskb->dev); | ||
| 398 | kfree_skb(nskb); | 385 | kfree_skb(nskb); |
| 399 | } else { | 386 | } else { |
| 400 | atomic_sub(confirm_recv, &iucv->msg_recv); | 387 | atomic_sub(confirm_recv, &iucv->msg_recv); |
| 401 | WARN_ON(atomic_read(&iucv->msg_recv) < 0); | 388 | WARN_ON(atomic_read(&iucv->msg_recv) < 0); |
| 402 | } | 389 | } |
| 403 | return err; | 390 | return net_xmit_eval(err); |
| 404 | } | 391 | } |
| 405 | 392 | ||
| 406 | static struct sock *__iucv_get_sock_by_name(char *nm) | 393 | static struct sock *__iucv_get_sock_by_name(char *nm) |
| @@ -471,7 +458,8 @@ static void iucv_sock_close(struct sock *sk) | |||
| 471 | { | 458 | { |
| 472 | struct iucv_sock *iucv = iucv_sk(sk); | 459 | struct iucv_sock *iucv = iucv_sk(sk); |
| 473 | unsigned long timeo; | 460 | unsigned long timeo; |
| 474 | int err, blen; | 461 | int err = 0; |
| 462 | int blen; | ||
| 475 | struct sk_buff *skb; | 463 | struct sk_buff *skb; |
| 476 | 464 | ||
| 477 | lock_sock(sk); | 465 | lock_sock(sk); |
| @@ -498,7 +486,7 @@ static void iucv_sock_close(struct sock *sk) | |||
| 498 | sk->sk_state = IUCV_CLOSING; | 486 | sk->sk_state = IUCV_CLOSING; |
| 499 | sk->sk_state_change(sk); | 487 | sk->sk_state_change(sk); |
| 500 | 488 | ||
| 501 | if (!skb_queue_empty(&iucv->send_skb_q)) { | 489 | if (!err && !skb_queue_empty(&iucv->send_skb_q)) { |
| 502 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) | 490 | if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) |
| 503 | timeo = sk->sk_lingertime; | 491 | timeo = sk->sk_lingertime; |
| 504 | else | 492 | else |
| @@ -515,13 +503,19 @@ static void iucv_sock_close(struct sock *sk) | |||
| 515 | sk->sk_err = ECONNRESET; | 503 | sk->sk_err = ECONNRESET; |
| 516 | sk->sk_state_change(sk); | 504 | sk->sk_state_change(sk); |
| 517 | 505 | ||
| 518 | iucv_skb_queue_purge(&iucv->send_skb_q); | 506 | skb_queue_purge(&iucv->send_skb_q); |
| 519 | skb_queue_purge(&iucv->backlog_skb_q); | 507 | skb_queue_purge(&iucv->backlog_skb_q); |
| 520 | 508 | ||
| 521 | default: /* fall through */ | 509 | default: /* fall through */ |
| 522 | iucv_sever_path(sk, 1); | 510 | iucv_sever_path(sk, 1); |
| 523 | } | 511 | } |
| 524 | 512 | ||
| 513 | if (iucv->hs_dev) { | ||
| 514 | dev_put(iucv->hs_dev); | ||
| 515 | iucv->hs_dev = NULL; | ||
| 516 | sk->sk_bound_dev_if = 0; | ||
| 517 | } | ||
| 518 | |||
| 525 | /* mark socket for deletion by iucv_sock_kill() */ | 519 | /* mark socket for deletion by iucv_sock_kill() */ |
| 526 | sock_set_flag(sk, SOCK_ZAPPED); | 520 | sock_set_flag(sk, SOCK_ZAPPED); |
| 527 | 521 | ||
| @@ -713,7 +707,6 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
| 713 | goto done_unlock; | 707 | goto done_unlock; |
| 714 | 708 | ||
| 715 | /* Bind the socket */ | 709 | /* Bind the socket */ |
| 716 | |||
| 717 | if (pr_iucv) | 710 | if (pr_iucv) |
| 718 | if (!memcmp(sa->siucv_user_id, iucv_userid, 8)) | 711 | if (!memcmp(sa->siucv_user_id, iucv_userid, 8)) |
| 719 | goto vm_bind; /* VM IUCV transport */ | 712 | goto vm_bind; /* VM IUCV transport */ |
| @@ -727,6 +720,8 @@ static int iucv_sock_bind(struct socket *sock, struct sockaddr *addr, | |||
| 727 | memcpy(iucv->src_name, sa->siucv_name, 8); | 720 | memcpy(iucv->src_name, sa->siucv_name, 8); |
| 728 | memcpy(iucv->src_user_id, sa->siucv_user_id, 8); | 721 | memcpy(iucv->src_user_id, sa->siucv_user_id, 8); |
| 729 | sk->sk_bound_dev_if = dev->ifindex; | 722 | sk->sk_bound_dev_if = dev->ifindex; |
| 723 | iucv->hs_dev = dev; | ||
| 724 | dev_hold(dev); | ||
| 730 | sk->sk_state = IUCV_BOUND; | 725 | sk->sk_state = IUCV_BOUND; |
| 731 | iucv->transport = AF_IUCV_TRANS_HIPER; | 726 | iucv->transport = AF_IUCV_TRANS_HIPER; |
| 732 | if (!iucv->msglimit) | 727 | if (!iucv->msglimit) |
| @@ -1128,8 +1123,10 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1128 | noblock, &err); | 1123 | noblock, &err); |
| 1129 | else | 1124 | else |
| 1130 | skb = sock_alloc_send_skb(sk, len, noblock, &err); | 1125 | skb = sock_alloc_send_skb(sk, len, noblock, &err); |
| 1131 | if (!skb) | 1126 | if (!skb) { |
| 1127 | err = -ENOMEM; | ||
| 1132 | goto out; | 1128 | goto out; |
| 1129 | } | ||
| 1133 | if (iucv->transport == AF_IUCV_TRANS_HIPER) | 1130 | if (iucv->transport == AF_IUCV_TRANS_HIPER) |
| 1134 | skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN); | 1131 | skb_reserve(skb, sizeof(struct af_iucv_trans_hdr) + ETH_HLEN); |
| 1135 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { | 1132 | if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { |
| @@ -1152,6 +1149,7 @@ static int iucv_sock_sendmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1152 | /* increment and save iucv message tag for msg_completion cbk */ | 1149 | /* increment and save iucv message tag for msg_completion cbk */ |
| 1153 | txmsg.tag = iucv->send_tag++; | 1150 | txmsg.tag = iucv->send_tag++; |
| 1154 | memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); | 1151 | memcpy(CB_TAG(skb), &txmsg.tag, CB_TAG_LEN); |
| 1152 | |||
| 1155 | if (iucv->transport == AF_IUCV_TRANS_HIPER) { | 1153 | if (iucv->transport == AF_IUCV_TRANS_HIPER) { |
| 1156 | atomic_inc(&iucv->msg_sent); | 1154 | atomic_inc(&iucv->msg_sent); |
| 1157 | err = afiucv_hs_send(&txmsg, sk, skb, 0); | 1155 | err = afiucv_hs_send(&txmsg, sk, skb, 0); |
| @@ -1206,8 +1204,6 @@ release: | |||
| 1206 | return len; | 1204 | return len; |
| 1207 | 1205 | ||
| 1208 | fail: | 1206 | fail: |
| 1209 | if (skb->dev) | ||
| 1210 | dev_put(skb->dev); | ||
| 1211 | kfree_skb(skb); | 1207 | kfree_skb(skb); |
| 1212 | out: | 1208 | out: |
| 1213 | release_sock(sk); | 1209 | release_sock(sk); |
| @@ -1400,7 +1396,14 @@ static int iucv_sock_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
| 1400 | } | 1396 | } |
| 1401 | 1397 | ||
| 1402 | |||
