diff options
Diffstat (limited to 'net/smc')
-rw-r--r-- | net/smc/af_smc.c | 58 | ||||
-rw-r--r-- | net/smc/smc_close.c | 25 | ||||
-rw-r--r-- | net/smc/smc_close.h | 1 | ||||
-rw-r--r-- | net/smc/smc_ism.c | 5 | ||||
-rw-r--r-- | net/smc/smc_pnet.c | 3 |
5 files changed, 68 insertions, 24 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 77ef53596d18..6f869ef49b32 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c | |||
@@ -167,10 +167,9 @@ static int smc_release(struct socket *sock) | |||
167 | 167 | ||
168 | if (sk->sk_state == SMC_CLOSED) { | 168 | if (sk->sk_state == SMC_CLOSED) { |
169 | if (smc->clcsock) { | 169 | if (smc->clcsock) { |
170 | mutex_lock(&smc->clcsock_release_lock); | 170 | release_sock(sk); |
171 | sock_release(smc->clcsock); | 171 | smc_clcsock_release(smc); |
172 | smc->clcsock = NULL; | 172 | lock_sock(sk); |
173 | mutex_unlock(&smc->clcsock_release_lock); | ||
174 | } | 173 | } |
175 | if (!smc->use_fallback) | 174 | if (!smc->use_fallback) |
176 | smc_conn_free(&smc->conn); | 175 | smc_conn_free(&smc->conn); |
@@ -446,10 +445,19 @@ static void smc_link_save_peer_info(struct smc_link *link, | |||
446 | link->peer_mtu = clc->qp_mtu; | 445 | link->peer_mtu = clc->qp_mtu; |
447 | } | 446 | } |
448 | 447 | ||
448 | static void smc_switch_to_fallback(struct smc_sock *smc) | ||
449 | { | ||
450 | smc->use_fallback = true; | ||
451 | if (smc->sk.sk_socket && smc->sk.sk_socket->file) { | ||
452 | smc->clcsock->file = smc->sk.sk_socket->file; | ||
453 | smc->clcsock->file->private_data = smc->clcsock; | ||
454 | } | ||
455 | } | ||
456 | |||
449 | /* fall back during connect */ | 457 | /* fall back during connect */ |
450 | static int smc_connect_fallback(struct smc_sock *smc, int reason_code) | 458 | static int smc_connect_fallback(struct smc_sock *smc, int reason_code) |
451 | { | 459 | { |
452 | smc->use_fallback = true; | 460 | smc_switch_to_fallback(smc); |
453 | smc->fallback_rsn = reason_code; | 461 | smc->fallback_rsn = reason_code; |
454 | smc_copy_sock_settings_to_clc(smc); | 462 | smc_copy_sock_settings_to_clc(smc); |
455 | if (smc->sk.sk_state == SMC_INIT) | 463 | if (smc->sk.sk_state == SMC_INIT) |
@@ -775,10 +783,14 @@ static void smc_connect_work(struct work_struct *work) | |||
775 | smc->sk.sk_err = -rc; | 783 | smc->sk.sk_err = -rc; |
776 | 784 | ||
777 | out: | 785 | out: |
778 | if (smc->sk.sk_err) | 786 | if (!sock_flag(&smc->sk, SOCK_DEAD)) { |
779 | smc->sk.sk_state_change(&smc->sk); | 787 | if (smc->sk.sk_err) { |
780 | else | 788 | smc->sk.sk_state_change(&smc->sk); |
781 | smc->sk.sk_write_space(&smc->sk); | 789 | } else { /* allow polling before and after fallback decision */ |
790 | smc->clcsock->sk->sk_write_space(smc->clcsock->sk); | ||
791 | smc->sk.sk_write_space(&smc->sk); | ||
792 | } | ||
793 | } | ||
782 | kfree(smc->connect_info); | 794 | kfree(smc->connect_info); |
783 | smc->connect_info = NULL; | 795 | smc->connect_info = NULL; |
784 | release_sock(&smc->sk); | 796 | release_sock(&smc->sk); |
@@ -872,11 +884,11 @@ static int smc_clcsock_accept(struct smc_sock *lsmc, struct smc_sock **new_smc) | |||
872 | if (rc < 0) | 884 | if (rc < 0) |
873 | lsk->sk_err = -rc; | 885 | lsk->sk_err = -rc; |
874 | if (rc < 0 || lsk->sk_state == SMC_CLOSED) { | 886 | if (rc < 0 || lsk->sk_state == SMC_CLOSED) { |
887 | new_sk->sk_prot->unhash(new_sk); | ||
875 | if (new_clcsock) | 888 | if (new_clcsock) |
876 | sock_release(new_clcsock); | 889 | sock_release(new_clcsock); |
877 | new_sk->sk_state = SMC_CLOSED; | 890 | new_sk->sk_state = SMC_CLOSED; |
878 | sock_set_flag(new_sk, SOCK_DEAD); | 891 | sock_set_flag(new_sk, SOCK_DEAD); |
879 | new_sk->sk_prot->unhash(new_sk); | ||
880 | sock_put(new_sk); /* final */ | 892 | sock_put(new_sk); /* final */ |
881 | *new_smc = NULL; | 893 | *new_smc = NULL; |
882 | goto out; | 894 | goto out; |
@@ -927,16 +939,21 @@ struct sock *smc_accept_dequeue(struct sock *parent, | |||
927 | 939 | ||
928 | smc_accept_unlink(new_sk); | 940 | smc_accept_unlink(new_sk); |
929 | if (new_sk->sk_state == SMC_CLOSED) { | 941 | if (new_sk->sk_state == SMC_CLOSED) { |
942 | new_sk->sk_prot->unhash(new_sk); | ||
930 | if (isk->clcsock) { | 943 | if (isk->clcsock) { |
931 | sock_release(isk->clcsock); | 944 | sock_release(isk->clcsock); |
932 | isk->clcsock = NULL; | 945 | isk->clcsock = NULL; |
933 | } | 946 | } |
934 | new_sk->sk_prot->unhash(new_sk); | ||
935 | sock_put(new_sk); /* final */ | 947 | sock_put(new_sk); /* final */ |
936 | continue; | 948 | continue; |
937 | } | 949 | } |
938 | if (new_sock) | 950 | if (new_sock) { |
939 | sock_graft(new_sk, new_sock); | 951 | sock_graft(new_sk, new_sock); |
952 | if (isk->use_fallback) { | ||
953 | smc_sk(new_sk)->clcsock->file = new_sock->file; | ||
954 | isk->clcsock->file->private_data = isk->clcsock; | ||
955 | } | ||
956 | } | ||
940 | return new_sk; | 957 | return new_sk; |
941 | } | 958 | } |
942 | return NULL; | 959 | return NULL; |
@@ -956,6 +973,7 @@ void smc_close_non_accepted(struct sock *sk) | |||
956 | sock_set_flag(sk, SOCK_DEAD); | 973 | sock_set_flag(sk, SOCK_DEAD); |
957 | sk->sk_shutdown |= SHUTDOWN_MASK; | 974 | sk->sk_shutdown |= SHUTDOWN_MASK; |
958 | } | 975 | } |
976 | sk->sk_prot->unhash(sk); | ||
959 | if (smc->clcsock) { | 977 | if (smc->clcsock) { |
960 | struct socket *tcp; | 978 | struct socket *tcp; |
961 | 979 | ||
@@ -971,7 +989,6 @@ void smc_close_non_accepted(struct sock *sk) | |||
971 | smc_conn_free(&smc->conn); | 989 | smc_conn_free(&smc->conn); |
972 | } | 990 | } |
973 | release_sock(sk); | 991 | release_sock(sk); |
974 | sk->sk_prot->unhash(sk); | ||
975 | sock_put(sk); /* final sock_put */ | 992 | sock_put(sk); /* final sock_put */ |
976 | } | 993 | } |
977 | 994 | ||
@@ -1037,13 +1054,13 @@ static void smc_listen_out(struct smc_sock *new_smc) | |||
1037 | struct smc_sock *lsmc = new_smc->listen_smc; | 1054 | struct smc_sock *lsmc = new_smc->listen_smc; |
1038 | struct sock *newsmcsk = &new_smc->sk; | 1055 | struct sock *newsmcsk = &new_smc->sk; |
1039 | 1056 | ||
1040 | lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); | ||
1041 | if (lsmc->sk.sk_state == SMC_LISTEN) { | 1057 | if (lsmc->sk.sk_state == SMC_LISTEN) { |
1058 | lock_sock_nested(&lsmc->sk, SINGLE_DEPTH_NESTING); | ||
1042 | smc_accept_enqueue(&lsmc->sk, newsmcsk); | 1059 | smc_accept_enqueue(&lsmc->sk, newsmcsk); |
1060 | release_sock(&lsmc->sk); | ||
1043 | } else { /* no longer listening */ | 1061 | } else { /* no longer listening */ |
1044 | smc_close_non_accepted(newsmcsk); | 1062 | smc_close_non_accepted(newsmcsk); |
1045 | } | 1063 | } |
1046 | release_sock(&lsmc->sk); | ||
1047 | 1064 | ||
1048 | /* Wake up accept */ | 1065 | /* Wake up accept */ |
1049 | lsmc->sk.sk_data_ready(&lsmc->sk); | 1066 | lsmc->sk.sk_data_ready(&lsmc->sk); |
@@ -1087,7 +1104,7 @@ static void smc_listen_decline(struct smc_sock *new_smc, int reason_code, | |||
1087 | return; | 1104 | return; |
1088 | } | 1105 | } |
1089 | smc_conn_free(&new_smc->conn); | 1106 | smc_conn_free(&new_smc->conn); |
1090 | new_smc->use_fallback = true; | 1107 | smc_switch_to_fallback(new_smc); |
1091 | new_smc->fallback_rsn = reason_code; | 1108 | new_smc->fallback_rsn = reason_code; |
1092 | if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) { | 1109 | if (reason_code && reason_code != SMC_CLC_DECL_PEERDECL) { |
1093 | if (smc_clc_send_decline(new_smc, reason_code) < 0) { | 1110 | if (smc_clc_send_decline(new_smc, reason_code) < 0) { |
@@ -1237,6 +1254,9 @@ static void smc_listen_work(struct work_struct *work) | |||
1237 | int rc = 0; | 1254 | int rc = 0; |
1238 | u8 ibport; | 1255 | u8 ibport; |
1239 | 1256 | ||
1257 | if (new_smc->listen_smc->sk.sk_state != SMC_LISTEN) | ||
1258 | return smc_listen_out_err(new_smc); | ||
1259 | |||
1240 | if (new_smc->use_fallback) { | 1260 | if (new_smc->use_fallback) { |
1241 | smc_listen_out_connected(new_smc); | 1261 | smc_listen_out_connected(new_smc); |
1242 | return; | 1262 | return; |
@@ -1244,7 +1264,7 @@ static void smc_listen_work(struct work_struct *work) | |||
1244 | 1264 | ||
1245 | /* check if peer is smc capable */ | 1265 | /* check if peer is smc capable */ |
1246 | if (!tcp_sk(newclcsock->sk)->syn_smc) { | 1266 | if (!tcp_sk(newclcsock->sk)->syn_smc) { |
1247 | new_smc->use_fallback = true; | 1267 | smc_switch_to_fallback(new_smc); |
1248 | new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC; | 1268 | new_smc->fallback_rsn = SMC_CLC_DECL_PEERNOSMC; |
1249 | smc_listen_out_connected(new_smc); | 1269 | smc_listen_out_connected(new_smc); |
1250 | return; | 1270 | return; |
@@ -1501,7 +1521,7 @@ static int smc_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) | |||
1501 | 1521 | ||
1502 | if (msg->msg_flags & MSG_FASTOPEN) { | 1522 | if (msg->msg_flags & MSG_FASTOPEN) { |
1503 | if (sk->sk_state == SMC_INIT) { | 1523 | if (sk->sk_state == SMC_INIT) { |
1504 | smc->use_fallback = true; | 1524 | smc_switch_to_fallback(smc); |
1505 | smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; | 1525 | smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; |
1506 | } else { | 1526 | } else { |
1507 | rc = -EINVAL; | 1527 | rc = -EINVAL; |
@@ -1703,7 +1723,7 @@ static int smc_setsockopt(struct socket *sock, int level, int optname, | |||
1703 | case TCP_FASTOPEN_NO_COOKIE: | 1723 | case TCP_FASTOPEN_NO_COOKIE: |
1704 | /* option not supported by SMC */ | 1724 | /* option not supported by SMC */ |
1705 | if (sk->sk_state == SMC_INIT) { | 1725 | if (sk->sk_state == SMC_INIT) { |
1706 | smc->use_fallback = true; | 1726 | smc_switch_to_fallback(smc); |
1707 | smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; | 1727 | smc->fallback_rsn = SMC_CLC_DECL_OPTUNSUPP; |
1708 | } else { | 1728 | } else { |
1709 | if (!smc->use_fallback) | 1729 | if (!smc->use_fallback) |
diff --git a/net/smc/smc_close.c b/net/smc/smc_close.c index 2ad37e998509..fc06720b53c1 100644 --- a/net/smc/smc_close.c +++ b/net/smc/smc_close.c | |||
@@ -21,6 +21,22 @@ | |||
21 | 21 | ||
22 | #define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ) | 22 | #define SMC_CLOSE_WAIT_LISTEN_CLCSOCK_TIME (5 * HZ) |
23 | 23 | ||
24 | /* release the clcsock that is assigned to the smc_sock */ | ||
25 | void smc_clcsock_release(struct smc_sock *smc) | ||
26 | { | ||
27 | struct socket *tcp; | ||
28 | |||
29 | if (smc->listen_smc && current_work() != &smc->smc_listen_work) | ||
30 | cancel_work_sync(&smc->smc_listen_work); | ||
31 | mutex_lock(&smc->clcsock_release_lock); | ||
32 | if (smc->clcsock) { | ||
33 | tcp = smc->clcsock; | ||
34 | smc->clcsock = NULL; | ||
35 | sock_release(tcp); | ||
36 | } | ||
37 | mutex_unlock(&smc->clcsock_release_lock); | ||
38 | } | ||
39 | |||
24 | static void smc_close_cleanup_listen(struct sock *parent) | 40 | static void smc_close_cleanup_listen(struct sock *parent) |
25 | { | 41 | { |
26 | struct sock *sk; | 42 | struct sock *sk; |
@@ -321,6 +337,7 @@ static void smc_close_passive_work(struct work_struct *work) | |||
321 | close_work); | 337 | close_work); |
322 | struct smc_sock *smc = container_of(conn, struct smc_sock, conn); | 338 | struct smc_sock *smc = container_of(conn, struct smc_sock, conn); |
323 | struct smc_cdc_conn_state_flags *rxflags; | 339 | struct smc_cdc_conn_state_flags *rxflags; |
340 | bool release_clcsock = false; | ||
324 | struct sock *sk = &smc->sk; | 341 | struct sock *sk = &smc->sk; |
325 | int old_state; | 342 | int old_state; |
326 | 343 | ||
@@ -400,13 +417,13 @@ wakeup: | |||
400 | if ((sk->sk_state == SMC_CLOSED) && | 417 | if ((sk->sk_state == SMC_CLOSED) && |
401 | (sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) { | 418 | (sock_flag(sk, SOCK_DEAD) || !sk->sk_socket)) { |
402 | smc_conn_free(conn); | 419 | smc_conn_free(conn); |
403 | if (smc->clcsock) { | 420 | if (smc->clcsock) |
404 | sock_release(smc->clcsock); | 421 | release_clcsock = true; |
405 | smc->clcsock = NULL; | ||
406 | } | ||
407 | } | 422 | } |
408 | } | 423 | } |
409 | release_sock(sk); | 424 | release_sock(sk); |
425 | if (release_clcsock) | ||
426 | smc_clcsock_release(smc); | ||
410 | sock_put(sk); /* sock_hold done by schedulers of close_work */ | 427 | sock_put(sk); /* sock_hold done by schedulers of close_work */ |
411 | } | 428 | } |
412 | 429 | ||
diff --git a/net/smc/smc_close.h b/net/smc/smc_close.h index 19eb6a211c23..e0e3b5df25d2 100644 --- a/net/smc/smc_close.h +++ b/net/smc/smc_close.h | |||
@@ -23,5 +23,6 @@ void smc_close_wake_tx_prepared(struct smc_sock *smc); | |||
23 | int smc_close_active(struct smc_sock *smc); | 23 | int smc_close_active(struct smc_sock *smc); |
24 | int smc_close_shutdown_write(struct smc_sock *smc); | 24 | int smc_close_shutdown_write(struct smc_sock *smc); |
25 | void smc_close_init(struct smc_sock *smc); | 25 | void smc_close_init(struct smc_sock *smc); |
26 | void smc_clcsock_release(struct smc_sock *smc); | ||
26 | 27 | ||
27 | #endif /* SMC_CLOSE_H */ | 28 | #endif /* SMC_CLOSE_H */ |
diff --git a/net/smc/smc_ism.c b/net/smc/smc_ism.c index 2fff79db1a59..e89e918b88e0 100644 --- a/net/smc/smc_ism.c +++ b/net/smc/smc_ism.c | |||
@@ -289,6 +289,11 @@ struct smcd_dev *smcd_alloc_dev(struct device *parent, const char *name, | |||
289 | INIT_LIST_HEAD(&smcd->vlan); | 289 | INIT_LIST_HEAD(&smcd->vlan); |
290 | smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", | 290 | smcd->event_wq = alloc_ordered_workqueue("ism_evt_wq-%s)", |
291 | WQ_MEM_RECLAIM, name); | 291 | WQ_MEM_RECLAIM, name); |
292 | if (!smcd->event_wq) { | ||
293 | kfree(smcd->conn); | ||
294 | kfree(smcd); | ||
295 | return NULL; | ||
296 | } | ||
292 | return smcd; | 297 | return smcd; |
293 | } | 298 | } |
294 | EXPORT_SYMBOL_GPL(smcd_alloc_dev); | 299 | EXPORT_SYMBOL_GPL(smcd_alloc_dev); |
diff --git a/net/smc/smc_pnet.c b/net/smc/smc_pnet.c index 8d2f6296279c..0285c7f9e79b 100644 --- a/net/smc/smc_pnet.c +++ b/net/smc/smc_pnet.c | |||
@@ -603,7 +603,8 @@ static int smc_pnet_flush(struct sk_buff *skb, struct genl_info *info) | |||
603 | { | 603 | { |
604 | struct net *net = genl_info_net(info); | 604 | struct net *net = genl_info_net(info); |
605 | 605 | ||
606 | return smc_pnet_remove_by_pnetid(net, NULL); | 606 | smc_pnet_remove_by_pnetid(net, NULL); |
607 | return 0; | ||
607 | } | 608 | } |
608 | 609 | ||
609 | /* SMC_PNETID generic netlink operation definition */ | 610 | /* SMC_PNETID generic netlink operation definition */ |