|
| 1 | +tcp: add tcp_sock_set_cork |
| 2 | + |
| 3 | +jira LE-3571 |
| 4 | +Rebuild_History Non-Buildable kernel-4.18.0-553.60.1.el8_10 |
| 5 | +commit-author Christoph Hellwig <hch@lst.de> |
| 6 | +commit db10538a4b997a77a1fd561adaaa58afc7dcfa2f |
| 7 | +Empty-Commit: Cherry-Pick Conflicts during history rebuild. |
| 8 | +Will be included in final tarball splat. Ref for failed cherry-pick at: |
| 9 | +ciq/ciq_backports/kernel-4.18.0-553.60.1.el8_10/db10538a.failed |
| 10 | + |
| 11 | +Add a helper to directly set the TCP_CORK sockopt from kernel space |
| 12 | +without going through a fake uaccess. Cleanup the callers to avoid |
| 13 | +pointless wrappers now that this is a simple function call. |
| 14 | + |
| 15 | + Signed-off-by: Christoph Hellwig <hch@lst.de> |
| 16 | + Signed-off-by: David S. Miller <davem@davemloft.net> |
| 17 | +(cherry picked from commit db10538a4b997a77a1fd561adaaa58afc7dcfa2f) |
| 18 | + Signed-off-by: Jonathan Maple <jmaple@ciq.com> |
| 19 | + |
| 20 | +# Conflicts: |
| 21 | +# drivers/block/drbd/drbd_int.h |
| 22 | +# fs/cifs/transport.c |
| 23 | +# include/linux/tcp.h |
| 24 | +# net/ipv4/tcp.c |
| 25 | +diff --cc drivers/block/drbd/drbd_int.h |
| 26 | +index dd0e1606fd7e,3550adc93c68..000000000000 |
| 27 | +--- a/drivers/block/drbd/drbd_int.h |
| 28 | ++++ b/drivers/block/drbd/drbd_int.h |
| 29 | +@@@ -1574,17 -1570,10 +1574,24 @@@ extern void drbd_set_recv_tcq(struct dr |
| 30 | + extern void _drbd_clear_done_ee(struct drbd_device *device, struct list_head *to_be_freed); |
| 31 | + extern int drbd_connected(struct drbd_peer_device *); |
| 32 | + |
| 33 | +++<<<<<<< HEAD |
| 34 | + +static inline void drbd_tcp_cork(struct socket *sock) |
| 35 | + +{ |
| 36 | + + int val = 1; |
| 37 | + + (void) kernel_setsockopt(sock, SOL_TCP, TCP_CORK, |
| 38 | + + (char*)&val, sizeof(val)); |
| 39 | + +} |
| 40 | + + |
| 41 | + +static inline void drbd_tcp_uncork(struct socket *sock) |
| 42 | + +{ |
| 43 | + + int val = 0; |
| 44 | + + (void) kernel_setsockopt(sock, SOL_TCP, TCP_CORK, |
| 45 | +++======= |
| 46 | ++ static inline void drbd_tcp_nodelay(struct socket *sock) |
| 47 | ++ { |
| 48 | ++ int val = 1; |
| 49 | ++ (void) kernel_setsockopt(sock, SOL_TCP, TCP_NODELAY, |
| 50 | +++>>>>>>> db10538a4b99 (tcp: add tcp_sock_set_cork) |
| 51 | + (char*)&val, sizeof(val)); |
| 52 | + } |
| 53 | + |
| 54 | +diff --cc fs/cifs/transport.c |
| 55 | +index 81c73767363e,99760063e000..000000000000 |
| 56 | +--- a/fs/cifs/transport.c |
| 57 | ++++ b/fs/cifs/transport.c |
| 58 | +@@@ -298,8 -324,7 +298,12 @@@ __smb_send_rqst(struct TCP_Server_Info |
| 59 | + sigset_t mask, oldmask; |
| 60 | + size_t total_len = 0, sent, size; |
| 61 | + struct socket *ssocket = server->ssocket; |
| 62 | +++<<<<<<< HEAD |
| 63 | + + struct msghdr smb_msg = {}; |
| 64 | + + int val = 1; |
| 65 | +++======= |
| 66 | ++ struct msghdr smb_msg; |
| 67 | +++>>>>>>> db10538a4b99 (tcp: add tcp_sock_set_cork) |
| 68 | + __be32 rfc1002_marker; |
| 69 | + |
| 70 | + if (cifs_rdma_enabled(server)) { |
| 71 | +diff --cc include/linux/tcp.h |
| 72 | +index 2f7a01dcf5ea,889eeb2256c2..000000000000 |
| 73 | +--- a/include/linux/tcp.h |
| 74 | ++++ b/include/linux/tcp.h |
| 75 | +@@@ -543,9 -497,6 +543,13 @@@ static inline u16 tcp_mss_clamp(const s |
| 76 | + int tcp_skb_shift(struct sk_buff *to, struct sk_buff *from, int pcount, |
| 77 | + int shiftlen); |
| 78 | + |
| 79 | +++<<<<<<< HEAD |
| 80 | + +int tcp_sock_set_keepidle_locked(struct sock *sk, int val); |
| 81 | + +int tcp_sock_set_keepidle(struct sock *sk, int val); |
| 82 | + +void tcp_sock_set_nodelay(struct sock *sk); |
| 83 | + +int tcp_sock_set_syncnt(struct sock *sk, int val); |
| 84 | +++======= |
| 85 | ++ void tcp_sock_set_cork(struct sock *sk, bool on); |
| 86 | +++>>>>>>> db10538a4b99 (tcp: add tcp_sock_set_cork) |
| 87 | + |
| 88 | + #endif /* _LINUX_TCP_H */ |
| 89 | +diff --cc net/ipv4/tcp.c |
| 90 | +index 19a03d7b55d2,e6cf702e16d6..000000000000 |
| 91 | +--- a/net/ipv4/tcp.c |
| 92 | ++++ b/net/ipv4/tcp.c |
| 93 | +@@@ -2818,90 -2786,52 +2818,124 @@@ static int tcp_repair_options_est(struc |
| 94 | + return 0; |
| 95 | + } |
| 96 | + |
| 97 | + -DEFINE_STATIC_KEY_FALSE(tcp_tx_delay_enabled); |
| 98 | + -EXPORT_SYMBOL(tcp_tx_delay_enabled); |
| 99 | + +/* TCP_NODELAY is weaker than TCP_CORK, so that this option on corked socket is |
| 100 | + + * remembered, but it is not activated until cork is cleared. |
| 101 | + + * |
| 102 | + + * However, when TCP_NODELAY is set we make an explicit push, which overrides |
| 103 | + + * even TCP_CORK for currently queued segments. |
| 104 | + + */ |
| 105 | + +static void __tcp_sock_set_nodelay(struct sock *sk, bool on) |
| 106 | + +{ |
| 107 | + + if (on) { |
| 108 | + + tcp_sk(sk)->nonagle |= TCP_NAGLE_OFF|TCP_NAGLE_PUSH; |
| 109 | + + tcp_push_pending_frames(sk); |
| 110 | + + } else { |
| 111 | + + tcp_sk(sk)->nonagle &= ~TCP_NAGLE_OFF; |
| 112 | + + } |
| 113 | + +} |
| 114 | + + |
| 115 | +++<<<<<<< HEAD |
| 116 | + +void tcp_sock_set_nodelay(struct sock *sk) |
| 117 | + +{ |
| 118 | + + lock_sock(sk); |
| 119 | + + __tcp_sock_set_nodelay(sk, true); |
| 120 | + + release_sock(sk); |
| 121 | + +} |
| 122 | + +EXPORT_SYMBOL(tcp_sock_set_nodelay); |
| 123 | + |
| 124 | + -static void tcp_enable_tx_delay(void) |
| 125 | + +int tcp_sock_set_syncnt(struct sock *sk, int val) |
| 126 | + { |
| 127 | + - if (!static_branch_unlikely(&tcp_tx_delay_enabled)) { |
| 128 | + - static int __tcp_tx_delay_enabled = 0; |
| 129 | + + if (val < 1 || val > MAX_TCP_SYNCNT) |
| 130 | + + return -EINVAL; |
| 131 | + |
| 132 | + - if (cmpxchg(&__tcp_tx_delay_enabled, 0, 1) == 0) { |
| 133 | + - static_branch_enable(&tcp_tx_delay_enabled); |
| 134 | + - pr_info("TCP_TX_DELAY enabled\n"); |
| 135 | + - } |
| 136 | + + lock_sock(sk); |
| 137 | + + inet_csk(sk)->icsk_syn_retries = val; |
| 138 | + + release_sock(sk); |
| 139 | + + return 0; |
| 140 | + +} |
| 141 | + +EXPORT_SYMBOL(tcp_sock_set_syncnt); |
| 142 | + + |
| 143 | + +int tcp_sock_set_keepidle_locked(struct sock *sk, int val) |
| 144 | + +{ |
| 145 | + + struct tcp_sock *tp = tcp_sk(sk); |
| 146 | + + |
| 147 | + + if (val < 1 || val > MAX_TCP_KEEPIDLE) |
| 148 | + + return -EINVAL; |
| 149 | + + |
| 150 | + + tp->keepalive_time = val * HZ; |
| 151 | + + if (sock_flag(sk, SOCK_KEEPOPEN) && |
| 152 | + + !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { |
| 153 | + + u32 elapsed = keepalive_time_elapsed(tp); |
| 154 | + + |
| 155 | + + if (tp->keepalive_time > elapsed) |
| 156 | + + elapsed = tp->keepalive_time - elapsed; |
| 157 | + + else |
| 158 | + + elapsed = 0; |
| 159 | + + inet_csk_reset_keepalive_timer(sk, elapsed); |
| 160 | + } |
| 161 | + + |
| 162 | + + return 0; |
| 163 | + } |
| 164 | + |
| 165 | + +int tcp_sock_set_keepidle(struct sock *sk, int val) |
| 166 | + +{ |
| 167 | + + int err; |
| 168 | + + |
| 169 | + + lock_sock(sk); |
| 170 | + + err = tcp_sock_set_keepidle_locked(sk, val); |
| 171 | + + release_sock(sk); |
| 172 | + + return err; |
| 173 | + +} |
| 174 | + +EXPORT_SYMBOL(tcp_sock_set_keepidle); |
| 175 | + + |
| 176 | + +int tcp_set_window_clamp(struct sock *sk, int val) |
| 177 | + +{ |
| 178 | + + struct tcp_sock *tp = tcp_sk(sk); |
| 179 | + + |
| 180 | + + if (!val) { |
| 181 | + + if (sk->sk_state != TCP_CLOSE) |
| 182 | + + return -EINVAL; |
| 183 | + + tp->window_clamp = 0; |
| 184 | + + } else { |
| 185 | + + tp->window_clamp = val < SOCK_MIN_RCVBUF / 2 ? |
| 186 | + + SOCK_MIN_RCVBUF / 2 : val; |
| 187 | + + } |
| 188 | + + return 0; |
| 189 | + +} |
| 190 | + + |
| 191 | +++======= |
| 192 | ++ /* When set indicates to always queue non-full frames. Later the user clears |
| 193 | ++ * this option and we transmit any pending partial frames in the queue. This is |
| 194 | ++ * meant to be used alongside sendfile() to get properly filled frames when the |
| 195 | ++ * user (for example) must write out headers with a write() call first and then |
| 196 | ++ * use sendfile to send out the data parts. |
| 197 | ++ * |
| 198 | ++ * TCP_CORK can be set together with TCP_NODELAY and it is stronger than |
| 199 | ++ * TCP_NODELAY. |
| 200 | ++ */ |
| 201 | ++ static void __tcp_sock_set_cork(struct sock *sk, bool on) |
| 202 | ++ { |
| 203 | ++ struct tcp_sock *tp = tcp_sk(sk); |
| 204 | ++ |
| 205 | ++ if (on) { |
| 206 | ++ tp->nonagle |= TCP_NAGLE_CORK; |
| 207 | ++ } else { |
| 208 | ++ tp->nonagle &= ~TCP_NAGLE_CORK; |
| 209 | ++ if (tp->nonagle & TCP_NAGLE_OFF) |
| 210 | ++ tp->nonagle |= TCP_NAGLE_PUSH; |
| 211 | ++ tcp_push_pending_frames(sk); |
| 212 | ++ } |
| 213 | ++ } |
| 214 | ++ |
| 215 | ++ void tcp_sock_set_cork(struct sock *sk, bool on) |
| 216 | ++ { |
| 217 | ++ lock_sock(sk); |
| 218 | ++ __tcp_sock_set_cork(sk, on); |
| 219 | ++ release_sock(sk); |
| 220 | ++ } |
| 221 | ++ EXPORT_SYMBOL(tcp_sock_set_cork); |
| 222 | ++ |
| 223 | +++>>>>>>> db10538a4b99 (tcp: add tcp_sock_set_cork) |
| 224 | + /* |
| 225 | + * Socket option code for TCP. |
| 226 | + */ |
| 227 | +* Unmerged path drivers/block/drbd/drbd_int.h |
| 228 | +diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c |
| 229 | +index 1c486b55de07..5725289429c6 100644 |
| 230 | +--- a/drivers/block/drbd/drbd_receiver.c |
| 231 | ++++ b/drivers/block/drbd/drbd_receiver.c |
| 232 | +@@ -5974,7 +5974,7 @@ void drbd_send_acks_wf(struct work_struct *ws) |
| 233 | + rcu_read_unlock(); |
| 234 | + |
| 235 | + if (tcp_cork) |
| 236 | +- drbd_tcp_cork(connection->meta.socket); |
| 237 | ++ tcp_sock_set_cork(connection->meta.socket->sk, true); |
| 238 | + |
| 239 | + err = drbd_finish_peer_reqs(device); |
| 240 | + kref_put(&device->kref, drbd_destroy_device); |
| 241 | +@@ -5987,7 +5987,7 @@ void drbd_send_acks_wf(struct work_struct *ws) |
| 242 | + } |
| 243 | + |
| 244 | + if (tcp_cork) |
| 245 | +- drbd_tcp_uncork(connection->meta.socket); |
| 246 | ++ tcp_sock_set_cork(connection->meta.socket->sk, false); |
| 247 | + |
| 248 | + return; |
| 249 | + } |
| 250 | +diff --git a/drivers/block/drbd/drbd_worker.c b/drivers/block/drbd/drbd_worker.c |
| 251 | +index 1615be162131..a29ee3da8334 100644 |
| 252 | +--- a/drivers/block/drbd/drbd_worker.c |
| 253 | ++++ b/drivers/block/drbd/drbd_worker.c |
| 254 | +@@ -2110,7 +2110,7 @@ static void wait_for_work(struct drbd_connection *connection, struct list_head * |
| 255 | + if (uncork) { |
| 256 | + mutex_lock(&connection->data.mutex); |
| 257 | + if (connection->data.socket) |
| 258 | +- drbd_tcp_uncork(connection->data.socket); |
| 259 | ++ tcp_sock_set_cork(connection->data.socket->sk, false); |
| 260 | + mutex_unlock(&connection->data.mutex); |
| 261 | + } |
| 262 | + |
| 263 | +@@ -2165,9 +2165,9 @@ static void wait_for_work(struct drbd_connection *connection, struct list_head * |
| 264 | + mutex_lock(&connection->data.mutex); |
| 265 | + if (connection->data.socket) { |
| 266 | + if (cork) |
| 267 | +- drbd_tcp_cork(connection->data.socket); |
| 268 | ++ tcp_sock_set_cork(connection->data.socket->sk, true); |
| 269 | + else if (!uncork) |
| 270 | +- drbd_tcp_uncork(connection->data.socket); |
| 271 | ++ tcp_sock_set_cork(connection->data.socket->sk, false); |
| 272 | + } |
| 273 | + mutex_unlock(&connection->data.mutex); |
| 274 | + } |
| 275 | +* Unmerged path fs/cifs/transport.c |
| 276 | +* Unmerged path include/linux/tcp.h |
| 277 | +* Unmerged path net/ipv4/tcp.c |
| 278 | +diff --git a/net/rds/tcp_send.c b/net/rds/tcp_send.c |
| 279 | +index 7df869d37afd..2398e72a1263 100644 |
| 280 | +--- a/net/rds/tcp_send.c |
| 281 | ++++ b/net/rds/tcp_send.c |
| 282 | +@@ -38,23 +38,18 @@ |
| 283 | + #include "rds.h" |
| 284 | + #include "tcp.h" |
| 285 | + |
| 286 | +-static void rds_tcp_cork(struct socket *sock, int val) |
| 287 | +-{ |
| 288 | +- kernel_setsockopt(sock, SOL_TCP, TCP_CORK, (void *)&val, sizeof(val)); |
| 289 | +-} |
| 290 | +- |
| 291 | + void rds_tcp_xmit_path_prepare(struct rds_conn_path *cp) |
| 292 | + { |
| 293 | + struct rds_tcp_connection *tc = cp->cp_transport_data; |
| 294 | + |
| 295 | +- rds_tcp_cork(tc->t_sock, 1); |
| 296 | ++ tcp_sock_set_cork(tc->t_sock->sk, true); |
| 297 | + } |
| 298 | + |
| 299 | + void rds_tcp_xmit_path_complete(struct rds_conn_path *cp) |
| 300 | + { |
| 301 | + struct rds_tcp_connection *tc = cp->cp_transport_data; |
| 302 | + |
| 303 | +- rds_tcp_cork(tc->t_sock, 0); |
| 304 | ++ tcp_sock_set_cork(tc->t_sock->sk, false); |
| 305 | + } |
| 306 | + |
| 307 | + /* the core send_sem serializes this with other xmit and shutdown */ |
0 commit comments