summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorUrsula Braun <ubraun@linux.ibm.com>2018-04-26 11:18:23 -0400
committerDavid S. Miller <davem@davemloft.net>2018-04-27 14:02:52 -0400
commitabb190f194d082cbb7520e692d78d3ddf050e7b1 (patch)
treecd5aa5a266ed465ffaf10810a058234d672fb8fe /net
parent01d2f7e2cdd31becffafa0cb82809a5e36558ec0 (diff)
net/smc: handle sockopt TCP_DEFER_ACCEPT
If sockopt TCP_DEFER_ACCEPT is set, the accept is delayed till data is available. Signed-off-by: Ursula Braun <ubraun@linux.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/smc/af_smc.c26
-rw-r--r--net/smc/smc.h4
-rw-r--r--net/smc/smc_rx.c2
-rw-r--r--net/smc/smc_rx.h1
4 files changed, 31 insertions, 2 deletions
diff --git a/net/smc/af_smc.c b/net/smc/af_smc.c
index 9d8b381281e3..20aa4175b9f8 100644
--- a/net/smc/af_smc.c
+++ b/net/smc/af_smc.c
@@ -1044,6 +1044,7 @@ static int smc_accept(struct socket *sock, struct socket *new_sock,
1044 1044
1045 if (lsmc->sk.sk_state != SMC_LISTEN) { 1045 if (lsmc->sk.sk_state != SMC_LISTEN) {
1046 rc = -EINVAL; 1046 rc = -EINVAL;
1047 release_sock(sk);
1047 goto out; 1048 goto out;
1048 } 1049 }
1049 1050
@@ -1071,9 +1072,29 @@ static int smc_accept(struct socket *sock, struct socket *new_sock,
1071 1072
1072 if (!rc) 1073 if (!rc)
1073 rc = sock_error(nsk); 1074 rc = sock_error(nsk);
1075 release_sock(sk);
1076 if (rc)
1077 goto out;
1078
1079 if (lsmc->sockopt_defer_accept && !(flags & O_NONBLOCK)) {
1080 /* wait till data arrives on the socket */
1081 timeo = msecs_to_jiffies(lsmc->sockopt_defer_accept *
1082 MSEC_PER_SEC);
1083 if (smc_sk(nsk)->use_fallback) {
1084 struct sock *clcsk = smc_sk(nsk)->clcsock->sk;
1085
1086 lock_sock(clcsk);
1087 if (skb_queue_empty(&clcsk->sk_receive_queue))
1088 sk_wait_data(clcsk, &timeo, NULL);
1089 release_sock(clcsk);
1090 } else if (!atomic_read(&smc_sk(nsk)->conn.bytes_to_rcv)) {
1091 lock_sock(nsk);
1092 smc_rx_wait_data(smc_sk(nsk), &timeo);
1093 release_sock(nsk);
1094 }
1095 }
1074 1096
1075out: 1097out:
1076 release_sock(sk);
1077 sock_put(sk); /* sock_hold above */ 1098 sock_put(sk); /* sock_hold above */
1078 return rc; 1099 return rc;
1079} 1100}
@@ -1340,6 +1361,9 @@ static int smc_setsockopt(struct socket *sock, int level, int optname,
1340 0); 1361 0);
1341 } 1362 }
1342 break; 1363 break;
1364 case TCP_DEFER_ACCEPT:
1365 smc->sockopt_defer_accept = val;
1366 break;
1343 default: 1367 default:
1344 break; 1368 break;
1345 } 1369 }
diff --git a/net/smc/smc.h b/net/smc/smc.h
index e4829a2f46ba..2405e889b93d 100644
--- a/net/smc/smc.h
+++ b/net/smc/smc.h
@@ -180,6 +180,10 @@ struct smc_sock { /* smc sock container */
180 struct list_head accept_q; /* sockets to be accepted */ 180 struct list_head accept_q; /* sockets to be accepted */
181 spinlock_t accept_q_lock; /* protects accept_q */ 181 spinlock_t accept_q_lock; /* protects accept_q */
182 bool use_fallback; /* fallback to tcp */ 182 bool use_fallback; /* fallback to tcp */
183 int sockopt_defer_accept;
184 /* sockopt TCP_DEFER_ACCEPT
185 * value
186 */
183 u8 wait_close_tx_prepared : 1; 187 u8 wait_close_tx_prepared : 1;
184 /* shutdown wr or close 188 /* shutdown wr or close
185 * started, waiting for unsent 189 * started, waiting for unsent
diff --git a/net/smc/smc_rx.c b/net/smc/smc_rx.c
index eff4e0d0bb31..af851d8df1f8 100644
--- a/net/smc/smc_rx.c
+++ b/net/smc/smc_rx.c
@@ -51,7 +51,7 @@ static void smc_rx_data_ready(struct sock *sk)
51 * 1 if at least 1 byte available in rcvbuf or if socket error/shutdown. 51 * 1 if at least 1 byte available in rcvbuf or if socket error/shutdown.
52 * 0 otherwise (nothing in rcvbuf nor timeout, e.g. interrupted). 52 * 0 otherwise (nothing in rcvbuf nor timeout, e.g. interrupted).
53 */ 53 */
54static int smc_rx_wait_data(struct smc_sock *smc, long *timeo) 54int smc_rx_wait_data(struct smc_sock *smc, long *timeo)
55{ 55{
56 DEFINE_WAIT_FUNC(wait, woken_wake_function); 56 DEFINE_WAIT_FUNC(wait, woken_wake_function);
57 struct smc_connection *conn = &smc->conn; 57 struct smc_connection *conn = &smc->conn;
diff --git a/net/smc/smc_rx.h b/net/smc/smc_rx.h
index 3a32b59bf06c..0b75a6b470e6 100644
--- a/net/smc/smc_rx.h
+++ b/net/smc/smc_rx.h
@@ -20,5 +20,6 @@
20void smc_rx_init(struct smc_sock *smc); 20void smc_rx_init(struct smc_sock *smc);
21int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, size_t len, 21int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, size_t len,
22 int flags); 22 int flags);
23int smc_rx_wait_data(struct smc_sock *smc, long *timeo);
23 24
24#endif /* SMC_RX_H */ 25#endif /* SMC_RX_H */