diff options
author | Ursula Braun <ubraun@linux.ibm.com> | 2018-04-26 11:18:23 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-04-27 14:02:52 -0400 |
commit | abb190f194d082cbb7520e692d78d3ddf050e7b1 (patch) | |
tree | cd5aa5a266ed465ffaf10810a058234d672fb8fe /net | |
parent | 01d2f7e2cdd31becffafa0cb82809a5e36558ec0 (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.c | 26 | ||||
-rw-r--r-- | net/smc/smc.h | 4 | ||||
-rw-r--r-- | net/smc/smc_rx.c | 2 | ||||
-rw-r--r-- | net/smc/smc_rx.h | 1 |
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 | ||
1075 | out: | 1097 | out: |
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 | */ |
54 | static int smc_rx_wait_data(struct smc_sock *smc, long *timeo) | 54 | int 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 @@ | |||
20 | void smc_rx_init(struct smc_sock *smc); | 20 | void smc_rx_init(struct smc_sock *smc); |
21 | int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, size_t len, | 21 | int smc_rx_recvmsg(struct smc_sock *smc, struct msghdr *msg, size_t len, |
22 | int flags); | 22 | int flags); |
23 | int smc_rx_wait_data(struct smc_sock *smc, long *timeo); | ||
23 | 24 | ||
24 | #endif /* SMC_RX_H */ | 25 | #endif /* SMC_RX_H */ |