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 | |
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>
-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; |