diff options
| author | Ursula Braun <ursula.braun@de.ibm.com> | 2012-02-07 19:19:45 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2012-02-08 18:50:19 -0500 |
| commit | 7d316b9453523498246e9e19a659c423d4c5081e (patch) | |
| tree | 3031f461bd53a31ade520efae13f427e1fc4c3ab /net/iucv | |
| parent | 1ab0d2ec9aeb4489c05158e8a2b00bad89f67e03 (diff) | |
af_iucv: remove IUCV-pathes completely
A SEVER is missing in the callback of a receiving SEVERED. This may
inhibit z/VM to remove the corresponding IUCV-path completely.
This patch adds a SEVER in iucv_callback_connrej (together with
additional locking.
Signed-off-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Frank Blaschka <frank.blaschka@de.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/iucv')
| -rw-r--r-- | net/iucv/af_iucv.c | 71 |
1 files changed, 37 insertions, 34 deletions
diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c index d5c5b8fd1d01..3ce0259499ed 100644 --- a/net/iucv/af_iucv.c +++ b/net/iucv/af_iucv.c | |||
| @@ -90,6 +90,7 @@ do { \ | |||
| 90 | 90 | ||
| 91 | static void iucv_sock_kill(struct sock *sk); | 91 | static void iucv_sock_kill(struct sock *sk); |
| 92 | static void iucv_sock_close(struct sock *sk); | 92 | static void iucv_sock_close(struct sock *sk); |
| 93 | static void iucv_sever_path(struct sock *, int); | ||
| 93 | 94 | ||
| 94 | static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, | 95 | static int afiucv_hs_rcv(struct sk_buff *skb, struct net_device *dev, |
| 95 | struct packet_type *pt, struct net_device *orig_dev); | 96 | struct packet_type *pt, struct net_device *orig_dev); |
| @@ -181,11 +182,7 @@ static int afiucv_pm_freeze(struct device *dev) | |||
| 181 | case IUCV_DISCONN: | 182 | case IUCV_DISCONN: |
| 182 | case IUCV_CLOSING: | 183 | case IUCV_CLOSING: |
| 183 | case IUCV_CONNECTED: | 184 | case IUCV_CONNECTED: |
| 184 | if (iucv->path) { | 185 | iucv_sever_path(sk, 0); |
| 185 | err = pr_iucv->path_sever(iucv->path, NULL); | ||
| 186 | iucv_path_free(iucv->path); | ||
| 187 | iucv->path = NULL; | ||
| 188 | } | ||
| 189 | break; | 186 | break; |
| 190 | case IUCV_OPEN: | 187 | case IUCV_OPEN: |
| 191 | case IUCV_BOUND: | 188 | case IUCV_BOUND: |
| @@ -194,6 +191,8 @@ static int afiucv_pm_freeze(struct device *dev) | |||
| 194 | default: | 191 | default: |
| 195 | break; | 192 | break; |
| 196 | } | 193 | } |
| 194 | skb_queue_purge(&iucv->send_skb_q); | ||
| 195 | skb_queue_purge(&iucv->backlog_skb_q); | ||
| 197 | } | 196 | } |
| 198 | read_unlock(&iucv_sk_list.lock); | 197 | read_unlock(&iucv_sk_list.lock); |
| 199 | return err; | 198 | return err; |
| @@ -447,10 +446,29 @@ static void iucv_sock_kill(struct sock *sk) | |||
| 447 | sock_put(sk); | 446 | sock_put(sk); |
| 448 | } | 447 | } |
| 449 | 448 | ||
| 449 | /* Terminate an IUCV path */ | ||
| 450 | static void iucv_sever_path(struct sock *sk, int with_user_data) | ||
| 451 | { | ||
| 452 | unsigned char user_data[16]; | ||
| 453 | struct iucv_sock *iucv = iucv_sk(sk); | ||
| 454 | struct iucv_path *path = iucv->path; | ||
| 455 | |||
| 456 | if (iucv->path) { | ||
| 457 | iucv->path = NULL; | ||
| 458 | if (with_user_data) { | ||
| 459 | low_nmcpy(user_data, iucv->src_name); | ||
| 460 | high_nmcpy(user_data, iucv->dst_name); | ||
| 461 | ASCEBC(user_data, sizeof(user_data)); | ||
| 462 | pr_iucv->path_sever(path, user_data); | ||
| 463 | } else | ||
| 464 | pr_iucv->path_sever(path, NULL); | ||
| 465 | iucv_path_free(path); | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 450 | /* Close an IUCV socket */ | 469 | /* Close an IUCV socket */ |
| 451 | static void iucv_sock_close(struct sock *sk) | 470 | static void iucv_sock_close(struct sock *sk) |
| 452 | { | 471 | { |
| 453 | unsigned char user_data[16]; | ||
| 454 | struct iucv_sock *iucv = iucv_sk(sk); | 472 | struct iucv_sock *iucv = iucv_sk(sk); |
| 455 | unsigned long timeo; | 473 | unsigned long timeo; |
| 456 | int err, blen; | 474 | int err, blen; |
| @@ -494,25 +512,14 @@ static void iucv_sock_close(struct sock *sk) | |||
| 494 | sk->sk_state = IUCV_CLOSED; | 512 | sk->sk_state = IUCV_CLOSED; |
| 495 | sk->sk_state_change(sk); | 513 | sk->sk_state_change(sk); |
| 496 | 514 | ||
| 497 | if (iucv->path) { | ||
| 498 | low_nmcpy(user_data, iucv->src_name); | ||
| 499 | high_nmcpy(user_data, iucv->dst_name); | ||
| 500 | ASCEBC(user_data, sizeof(user_data)); | ||
| 501 | pr_iucv->path_sever(iucv->path, user_data); | ||
| 502 | iucv_path_free(iucv->path); | ||
| 503 | iucv->path = NULL; | ||
| 504 | } | ||
| 505 | |||
| 506 | sk->sk_err = ECONNRESET; | 515 | sk->sk_err = ECONNRESET; |
| 507 | sk->sk_state_change(sk); | 516 | sk->sk_state_change(sk); |
| 508 | 517 | ||
| 509 | iucv_skb_queue_purge(&iucv->send_skb_q); | 518 | iucv_skb_queue_purge(&iucv->send_skb_q); |
| 510 | skb_queue_purge(&iucv->backlog_skb_q); | 519 | skb_queue_purge(&iucv->backlog_skb_q); |
| 511 | break; | ||
| 512 | 520 | ||
| 513 | default: | 521 | default: /* fall through */ |
| 514 | /* nothing to do here */ | 522 | iucv_sever_path(sk, 1); |
| 515 | break; | ||
| 516 | } | 523 | } |
| 517 | 524 | ||
| 518 | /* mark socket for deletion by iucv_sock_kill() */ | 525 | /* mark socket for deletion by iucv_sock_kill() */ |
| @@ -894,11 +901,8 @@ static int iucv_sock_connect(struct socket *sock, struct sockaddr *addr, | |||
| 894 | if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED) | 901 | if (sk->sk_state == IUCV_DISCONN || sk->sk_state == IUCV_CLOSED) |
| 895 | err = -ECONNREFUSED; | 902 | err = -ECONNREFUSED; |
| 896 | 903 | ||
| 897 | if (err && iucv->transport == AF_IUCV_TRANS_IUCV) { | 904 | if (err && iucv->transport == AF_IUCV_TRANS_IUCV) |
| 898 | pr_iucv->path_sever(iucv->path, NULL); | 905 | iucv_sever_path(sk, 0); |
| 899 | iucv_path_free(iucv->path); | ||
| 900 | iucv->path = NULL; | ||
| 901 | } | ||
| 902 | 906 | ||
| 903 | done: | 907 | done: |
| 904 | release_sock(sk); | 908 | release_sock(sk); |
| @@ -1565,13 +1569,6 @@ static int iucv_sock_release(struct socket *sock) | |||
| 1565 | 1569 | ||
| 1566 | iucv_sock_close(sk); | 1570 | iucv_sock_close(sk); |
| 1567 | 1571 | ||
| 1568 | /* Unregister with IUCV base support */ | ||
| 1569 | if (iucv_sk(sk)->path) { | ||
| 1570 | pr_iucv->path_sever(iucv_sk(sk)->path, NULL); | ||
| 1571 | iucv_path_free(iucv_sk(sk)->path); | ||
| 1572 | iucv_sk(sk)->path = NULL; | ||
| 1573 | } | ||
| 1574 | |||
| 1575 | sock_orphan(sk); | 1572 | sock_orphan(sk); |
| 1576 | iucv_sock_kill(sk); | 1573 | iucv_sock_kill(sk); |
| 1577 | return err; | 1574 | return err; |
| @@ -1750,8 +1747,7 @@ static int iucv_callback_connreq(struct iucv_path *path, | |||
| 1750 | path->msglim = iucv->msglimit; | 1747 | path->msglim = iucv->msglimit; |
| 1751 | err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk); | 1748 | err = pr_iucv->path_accept(path, &af_iucv_handler, nuser_data, nsk); |
| 1752 | if (err) { | 1749 | if (err) { |
| 1753 | err = pr_iucv->path_sever(path, user_data); | 1750 | iucv_sever_path(nsk, 1); |
| 1754 | iucv_path_free(path); | ||
| 1755 | iucv_sock_kill(nsk); | 1751 | iucv_sock_kill(nsk); |
| 1756 | goto fail; | 1752 | goto fail; |
| 1757 | } | 1753 | } |
| @@ -1828,6 +1824,7 @@ static void iucv_callback_txdone(struct iucv_path *path, | |||
| 1828 | struct sk_buff *list_skb = list->next; | 1824 | struct sk_buff *list_skb = list->next; |
| 1829 | unsigned long flags; | 1825 | unsigned long flags; |
| 1830 | 1826 | ||
| 1827 | bh_lock_sock(sk); | ||
| 1831 | if (!skb_queue_empty(list)) { | 1828 | if (!skb_queue_empty(list)) { |
| 1832 | spin_lock_irqsave(&list->lock, flags); | 1829 | spin_lock_irqsave(&list->lock, flags); |
| 1833 | 1830 | ||
| @@ -1849,7 +1846,6 @@ static void iucv_callback_txdone(struct iucv_path *path, | |||
| 1849 | iucv_sock_wake_msglim(sk); | 1846 | iucv_sock_wake_msglim(sk); |
| 1850 | } | 1847 | } |
| 1851 | } | 1848 | } |
| 1852 | BUG_ON(!this); | ||
| 1853 | 1849 | ||
| 1854 | if (sk->sk_state == IUCV_CLOSING) { | 1850 | if (sk->sk_state == IUCV_CLOSING) { |
| 1855 | if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { | 1851 | if (skb_queue_empty(&iucv_sk(sk)->send_skb_q)) { |
| @@ -1857,6 +1853,7 @@ static void iucv_callback_txdone(struct iucv_path *path, | |||
| 1857 | sk->sk_state_change(sk); | 1853 | sk->sk_state_change(sk); |
| 1858 | } | 1854 | } |
| 1859 | } | 1855 | } |
| 1856 | bh_unlock_sock(sk); | ||
| 1860 | 1857 | ||
| 1861 | } | 1858 | } |
| 1862 | 1859 | ||
| @@ -1864,9 +1861,15 @@ static void iucv_callback_connrej(struct iucv_path *path, u8 ipuser[16]) | |||
| 1864 | { | 1861 | { |
| 1865 | struct sock *sk = path->private; | 1862 | struct sock *sk = path->private; |
| 1866 | 1863 | ||
| 1864 | if (sk->sk_state == IUCV_CLOSED) | ||
| 1865 | return; | ||
| 1866 | |||
| 1867 | bh_lock_sock(sk); | ||
| 1868 | iucv_sever_path(sk, 1); | ||
| 1867 | sk->sk_state = IUCV_DISCONN; | 1869 | sk->sk_state = IUCV_DISCONN; |
| 1868 | 1870 | ||
| 1869 | sk->sk_state_change(sk); | 1871 | sk->sk_state_change(sk); |
| 1872 | bh_unlock_sock(sk); | ||
| 1870 | } | 1873 | } |
| 1871 | 1874 | ||
| 1872 | /* called if the other communication side shuts down its RECV direction; | 1875 | /* called if the other communication side shuts down its RECV direction; |
