diff options
author | Ursula Braun <ubraun@linux.ibm.com> | 2019-04-12 06:57:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2019-04-12 13:50:56 -0400 |
commit | 50717a37db032ce783f50685a73bb2ac68471a5a (patch) | |
tree | 8dd3d8070e52163f0c3fbfdadcb4224e3860915d | |
parent | 6dc400af216a79c10cb082f25a7337bcbf532045 (diff) |
net/smc: nonblocking connect rework
For nonblocking sockets move the kernel_connect() from the connect
worker into the initial smc_connect part to return kernel_connect()
errors other than -EINPROGRESS to user space.
Reviewed-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/smc/af_smc.c | 78 | ||||
-rw-r--r-- | net/smc/smc.h | 11 |
2 files changed, 47 insertions, 42 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c index 77ef53596d18..e1b7b5bdb440 100644 --- a/net/smc/af_smc.c +++ b/net/smc/af_smc.c | |||
@@ -134,11 +134,9 @@ static int smc_release(struct socket *sock) | |||
134 | smc = smc_sk(sk); | 134 | smc = smc_sk(sk); |
135 | 135 | ||
136 | /* cleanup for a dangling non-blocking connect */ | 136 | /* cleanup for a dangling non-blocking connect */ |
137 | if (smc->connect_info && sk->sk_state == SMC_INIT) | 137 | if (smc->connect_nonblock && sk->sk_state == SMC_INIT) |
138 | tcp_abort(smc->clcsock->sk, ECONNABORTED); | 138 | tcp_abort(smc->clcsock->sk, ECONNABORTED); |
139 | flush_work(&smc->connect_work); | 139 | flush_work(&smc->connect_work); |
140 | kfree(smc->connect_info); | ||
141 | smc->connect_info = NULL; | ||
142 | 140 | ||
143 | if (sk->sk_state == SMC_LISTEN) | 141 | if (sk->sk_state == SMC_LISTEN) |
144 | /* smc_close_non_accepted() is called and acquires | 142 | /* smc_close_non_accepted() is called and acquires |
@@ -452,6 +450,7 @@ static int smc_connect_fallback(struct smc_sock *smc, int reason_code) | |||
452 | smc->use_fallback = true; | 450 | smc->use_fallback = true; |
453 | smc->fallback_rsn = reason_code; | 451 | smc->fallback_rsn = reason_code; |
454 | smc_copy_sock_settings_to_clc(smc); | 452 | smc_copy_sock_settings_to_clc(smc); |
453 | smc->connect_nonblock = 0; | ||
455 | if (smc->sk.sk_state == SMC_INIT) | 454 | if (smc->sk.sk_state == SMC_INIT) |
456 | smc->sk.sk_state = SMC_ACTIVE; | 455 | smc->sk.sk_state = SMC_ACTIVE; |
457 | return 0; | 456 | return 0; |
@@ -491,6 +490,7 @@ static int smc_connect_abort(struct smc_sock *smc, int reason_code, | |||
491 | mutex_unlock(&smc_client_lgr_pending); | 490 | mutex_unlock(&smc_client_lgr_pending); |
492 | 491 | ||
493 | smc_conn_free(&smc->conn); | 492 | smc_conn_free(&smc->conn); |
493 | smc->connect_nonblock = 0; | ||
494 | return reason_code; | 494 | return reason_code; |
495 | } | 495 | } |
496 | 496 | ||
@@ -633,6 +633,7 @@ static int smc_connect_rdma(struct smc_sock *smc, | |||
633 | mutex_unlock(&smc_client_lgr_pending); | 633 | mutex_unlock(&smc_client_lgr_pending); |
634 | 634 | ||
635 | smc_copy_sock_settings_to_clc(smc); | 635 | smc_copy_sock_settings_to_clc(smc); |
636 | smc->connect_nonblock = 0; | ||
636 | if (smc->sk.sk_state == SMC_INIT) | 637 | if (smc->sk.sk_state == SMC_INIT) |
637 | smc->sk.sk_state = SMC_ACTIVE; | 638 | smc->sk.sk_state = SMC_ACTIVE; |
638 | 639 | ||
@@ -671,6 +672,7 @@ static int smc_connect_ism(struct smc_sock *smc, | |||
671 | mutex_unlock(&smc_server_lgr_pending); | 672 | mutex_unlock(&smc_server_lgr_pending); |
672 | 673 | ||
673 | smc_copy_sock_settings_to_clc(smc); | 674 | smc_copy_sock_settings_to_clc(smc); |
675 | smc->connect_nonblock = 0; | ||
674 | if (smc->sk.sk_state == SMC_INIT) | 676 | if (smc->sk.sk_state == SMC_INIT) |
675 | smc->sk.sk_state = SMC_ACTIVE; | 677 | smc->sk.sk_state = SMC_ACTIVE; |
676 | 678 | ||
@@ -756,17 +758,30 @@ static void smc_connect_work(struct work_struct *work) | |||
756 | { | 758 | { |
757 | struct smc_sock *smc = container_of(work, struct smc_sock, | 759 | struct smc_sock *smc = container_of(work, struct smc_sock, |
758 | connect_work); | 760 | connect_work); |
759 | int rc; | 761 | long timeo = smc->sk.sk_sndtimeo; |
762 | int rc = 0; | ||
760 | 763 | ||
761 | lock_sock(&smc->sk); | 764 | if (!timeo) |
762 | rc = kernel_connect(smc->clcsock, &smc->connect_info->addr, | 765 | timeo = MAX_SCHEDULE_TIMEOUT; |
763 | smc->connect_info->alen, smc->connect_info->flags); | 766 | lock_sock(smc->clcsock->sk); |
764 | if (smc->clcsock->sk->sk_err) { | 767 | if (smc->clcsock->sk->sk_err) { |
765 | smc->sk.sk_err = smc->clcsock->sk->sk_err; | 768 | smc->sk.sk_err = smc->clcsock->sk->sk_err; |
766 | goto out; | 769 | } else if ((1 << smc->clcsock->sk->sk_state) & |
767 | } | 770 | (TCPF_SYN_SENT | TCP_SYN_RECV)) { |
768 | if (rc < 0) { | 771 | rc = sk_stream_wait_connect(smc->clcsock->sk, &timeo); |
769 | smc->sk.sk_err = -rc; | 772 | if ((rc == -EPIPE) && |
773 | ((1 << smc->clcsock->sk->sk_state) & | ||
774 | (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT))) | ||
775 | rc = 0; | ||
776 | } | ||
777 | release_sock(smc->clcsock->sk); | ||
778 | lock_sock(&smc->sk); | ||
779 | if (rc != 0 || smc->sk.sk_err) { | ||
780 | smc->sk.sk_state = SMC_CLOSED; | ||
781 | if (rc == -EPIPE || rc == -EAGAIN) | ||
782 | smc->sk.sk_err = EPIPE; | ||
783 | else if (signal_pending(current)) | ||
784 | smc->sk.sk_err = -sock_intr_errno(timeo); | ||
770 | goto out; | 785 | goto out; |
771 | } | 786 | } |
772 | 787 | ||
@@ -779,8 +794,6 @@ out: | |||
779 | smc->sk.sk_state_change(&smc->sk); | 794 | smc->sk.sk_state_change(&smc->sk); |
780 | else | 795 | else |
781 | smc->sk.sk_write_space(&smc->sk); | 796 | smc->sk.sk_write_space(&smc->sk); |
782 | kfree(smc->connect_info); | ||
783 | smc->connect_info = NULL; | ||
784 | release_sock(&smc->sk); | 797 | release_sock(&smc->sk); |
785 | } | 798 | } |
786 | 799 | ||
@@ -813,26 +826,18 @@ static int smc_connect(struct socket *sock, struct sockaddr *addr, | |||
813 | 826 | ||
814 | smc_copy_sock_settings_to_clc(smc); | 827 | smc_copy_sock_settings_to_clc(smc); |
815 | tcp_sk(smc->clcsock->sk)->syn_smc = 1; | 828 | tcp_sk(smc->clcsock->sk)->syn_smc = 1; |
829 | if (smc->connect_nonblock) { | ||
830 | rc = -EALREADY; | ||
831 | goto out; | ||
832 | } | ||
833 | rc = kernel_connect(smc->clcsock, addr, alen, flags); | ||
834 | if (rc && rc != -EINPROGRESS) | ||
835 | goto out; | ||
816 | if (flags & O_NONBLOCK) { | 836 | if (flags & O_NONBLOCK) { |
817 | if (smc->connect_info) { | 837 | if (schedule_work(&smc->connect_work)) |
818 | rc = -EALREADY; | 838 | smc->connect_nonblock = 1; |
819 | goto out; | ||
820 | } | ||
821 | smc->connect_info = kzalloc(alen + 2 * sizeof(int), GFP_KERNEL); | ||
822 | if (!smc->connect_info) { | ||
823 | rc = -ENOMEM; | ||
824 | goto out; | ||
825 | } | ||
826 | smc->connect_info->alen = alen; | ||
827 | smc->connect_info->flags = flags ^ O_NONBLOCK; | ||
828 | memcpy(&smc->connect_info->addr, addr, alen); | ||
829 | schedule_work(&smc->connect_work); | ||
830 | rc = -EINPROGRESS; | 839 | rc = -EINPROGRESS; |
831 | } else { | 840 | } else { |
832 | rc = kernel_connect(smc->clcsock, addr, alen, flags); | ||
833 | if (rc) | ||
834 | goto out; | ||
835 | |||
836 | rc = __smc_connect(smc); | 841 | rc = __smc_connect(smc); |
837 | if (rc < 0) | 842 | if (rc < 0) |
838 | goto out; | 843 | goto out; |
@@ -1571,8 +1576,8 @@ static __poll_t smc_poll(struct file *file, struct socket *sock, | |||
1571 | poll_table *wait) | 1576 | poll_table *wait) |
1572 | { | 1577 | { |
1573 | struct sock *sk = sock->sk; | 1578 | struct sock *sk = sock->sk; |
1574 | __poll_t mask = 0; | ||
1575 | struct smc_sock *smc; | 1579 | struct smc_sock *smc; |
1580 | __poll_t mask = 0; | ||
1576 | 1581 | ||
1577 | if (!sk) | 1582 | if (!sk) |
1578 | return EPOLLNVAL; | 1583 | return EPOLLNVAL; |
@@ -1582,8 +1587,6 @@ static __poll_t smc_poll(struct file *file, struct socket *sock, | |||
1582 | /* delegate to CLC child sock */ | 1587 | /* delegate to CLC child sock */ |
1583 | mask = smc->clcsock->ops->poll(file, smc->clcsock, wait); | 1588 | mask = smc->clcsock->ops->poll(file, smc->clcsock, wait); |
1584 | sk->sk_err = smc->clcsock->sk->sk_err; | 1589 | sk->sk_err = smc->clcsock->sk->sk_err; |
1585 | if (sk->sk_err) | ||
1586 | mask |= EPOLLERR; | ||
1587 | } else { | 1590 | } else { |
1588 | if (sk->sk_state != SMC_CLOSED) | 1591 | if (sk->sk_state != SMC_CLOSED) |
1589 | sock_poll_wait(file, sock, wait); | 1592 | sock_poll_wait(file, sock, wait); |
@@ -1594,9 +1597,14 @@ static __poll_t smc_poll(struct file *file, struct socket *sock, | |||
1594 | mask |= EPOLLHUP; | 1597 | mask |= EPOLLHUP; |
1595 | if (sk->sk_state == SMC_LISTEN) { | 1598 | if (sk->sk_state == SMC_LISTEN) { |
1596 | /* woken up by sk_data_ready in smc_listen_work() */ | 1599 | /* woken up by sk_data_ready in smc_listen_work() */ |
1597 | mask = smc_accept_poll(sk); | 1600 | mask |= smc_accept_poll(sk); |
1601 | } else if (smc->use_fallback) { /* as result of connect_work()*/ | ||
1602 | mask |= smc->clcsock->ops->poll(file, smc->clcsock, | ||
1603 | wait); | ||
1604 | sk->sk_err = smc->clcsock->sk->sk_err; | ||
1598 | } else { | 1605 | } else { |
1599 | if (atomic_read(&smc->conn.sndbuf_space) || | 1606 | if ((sk->sk_state != SMC_INIT && |
1607 | atomic_read(&smc->conn.sndbuf_space)) || | ||
1600 | sk->sk_shutdown & SEND_SHUTDOWN) { | 1608 | sk->sk_shutdown & SEND_SHUTDOWN) { |
1601 | mask |= EPOLLOUT | EPOLLWRNORM; | 1609 | mask |= EPOLLOUT | EPOLLWRNORM; |
1602 | } else { | 1610 | } else { |
diff --git a/net/smc/smc.h b/net/smc/smc.h index adbdf195eb08..878313f8d6c1 100644 --- a/net/smc/smc.h +++ b/net/smc/smc.h | |||
@@ -190,18 +190,11 @@ struct smc_connection { | |||
190 | u64 peer_token; /* SMC-D token of peer */ | 190 | u64 peer_token; /* SMC-D token of peer */ |
191 | }; | 191 | }; |
192 | 192 | ||
193 | struct smc_connect_info { | ||
194 | int flags; | ||
195 | int alen; | ||
196 | struct sockaddr addr; | ||
197 | }; | ||
198 | |||
199 | struct smc_sock { /* smc sock container */ | 193 | struct smc_sock { /* smc sock container */ |
200 | struct sock sk; | 194 | struct sock sk; |
201 | struct socket *clcsock; /* internal tcp socket */ | 195 | struct socket *clcsock; /* internal tcp socket */ |
202 | struct smc_connection conn; /* smc connection */ | 196 | struct smc_connection conn; /* smc connection */ |
203 | struct smc_sock *listen_smc; /* listen parent */ | 197 | struct smc_sock *listen_smc; /* listen parent */ |
204 | struct smc_connect_info *connect_info; /* connect address & flags */ | ||
205 | struct work_struct connect_work; /* handle non-blocking connect*/ | 198 | struct work_struct connect_work; /* handle non-blocking connect*/ |
206 | struct work_struct tcp_listen_work;/* handle tcp socket accepts */ | 199 | struct work_struct tcp_listen_work;/* handle tcp socket accepts */ |
207 | struct work_struct smc_listen_work;/* prepare new accept socket */ | 200 | struct work_struct smc_listen_work;/* prepare new accept socket */ |
@@ -219,6 +212,10 @@ struct smc_sock { /* smc sock container */ | |||
219 | * started, waiting for unsent | 212 | * started, waiting for unsent |
220 | * data to be sent | 213 | * data to be sent |
221 | */ | 214 | */ |
215 | u8 connect_nonblock : 1; | ||
216 | /* non-blocking connect in | ||
217 | * flight | ||
218 | */ | ||
222 | struct mutex clcsock_release_lock; | 219 | struct mutex clcsock_release_lock; |
223 | /* protects clcsock of a listen | 220 | /* protects clcsock of a listen |
224 | * socket | 221 | * socket |