Blame view
net/rds/tcp_send.c
6.71 KB
70041088e RDS: Add TCP tran... |
1 |
/* |
eee2fa6ab rds: Changing IP ... |
2 |
* Copyright (c) 2006, 2017 Oracle and/or its affiliates. All rights reserved. |
70041088e RDS: Add TCP tran... |
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
* * This software is available to you under a choice of one of two * licenses. You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above * copyright notice, this list of conditions and the following * disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * */ #include <linux/kernel.h> #include <linux/in.h> #include <net/tcp.h> |
0cb43965d RDS: split out co... |
36 |
#include "rds_single_path.h" |
70041088e RDS: Add TCP tran... |
37 38 |
#include "rds.h" #include "tcp.h" |
226f7a7d9 RDS: Rework path ... |
39 |
void rds_tcp_xmit_path_prepare(struct rds_conn_path *cp) |
70041088e RDS: Add TCP tran... |
40 |
{ |
226f7a7d9 RDS: Rework path ... |
41 |
struct rds_tcp_connection *tc = cp->cp_transport_data; |
70041088e RDS: Add TCP tran... |
42 |
|
db10538a4 tcp: add tcp_sock... |
43 |
tcp_sock_set_cork(tc->t_sock->sk, true); |
70041088e RDS: Add TCP tran... |
44 |
} |
226f7a7d9 RDS: Rework path ... |
45 |
void rds_tcp_xmit_path_complete(struct rds_conn_path *cp) |
70041088e RDS: Add TCP tran... |
46 |
{ |
226f7a7d9 RDS: Rework path ... |
47 |
struct rds_tcp_connection *tc = cp->cp_transport_data; |
70041088e RDS: Add TCP tran... |
48 |
|
db10538a4 tcp: add tcp_sock... |
49 |
tcp_sock_set_cork(tc->t_sock->sk, false); |
70041088e RDS: Add TCP tran... |
50 51 52 |
} /* the core send_sem serializes this with other xmit and shutdown */ |
ff51bf841 rds: make local f... |
53 |
static int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len) |
70041088e RDS: Add TCP tran... |
54 55 |
{ struct kvec vec = { |
5c3da57d7 net: rds: fix cod... |
56 57 58 59 60 |
.iov_base = data, .iov_len = len, }; struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL, |
70041088e RDS: Add TCP tran... |
61 |
}; |
70041088e RDS: Add TCP tran... |
62 63 64 65 66 |
return kernel_sendmsg(sock, &msg, &vec, 1, vec.iov_len); } /* the core send_sem serializes this with other xmit and shutdown */ |
70041088e RDS: Add TCP tran... |
67 |
int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, |
5c3da57d7 net: rds: fix cod... |
68 |
unsigned int hdr_off, unsigned int sg, unsigned int off) |
70041088e RDS: Add TCP tran... |
69 |
{ |
5916e2c15 RDS: TCP: Enable ... |
70 71 |
struct rds_conn_path *cp = rm->m_inc.i_conn_path; struct rds_tcp_connection *tc = cp->cp_transport_data; |
70041088e RDS: Add TCP tran... |
72 73 |
int done = 0; int ret = 0; |
76b29ef12 RDS-TCP: Set up M... |
74 |
int more; |
70041088e RDS: Add TCP tran... |
75 76 77 78 79 80 |
if (hdr_off == 0) { /* * m_ack_seq is set to the sequence number of the last byte of * header and data. see rds_tcp_is_acked(). */ |
b589513e6 rds: tcp: compute... |
81 |
tc->t_last_sent_nxt = rds_tcp_write_seq(tc); |
70041088e RDS: Add TCP tran... |
82 83 84 |
rm->m_ack_seq = tc->t_last_sent_nxt + sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len) - 1; |
4e857c58e arch: Mass conver... |
85 |
smp_mb__before_atomic(); |
70041088e RDS: Add TCP tran... |
86 87 |
set_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags); tc->t_last_expected_una = rm->m_ack_seq + 1; |
315ca6d98 RDS: TCP: set RDS... |
88 89 |
if (test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) rm->m_inc.i_hdr.h_flags |= RDS_FLAG_RETRANSMITTED; |
70041088e RDS: Add TCP tran... |
90 91 |
rdsdebug("rm %p tcp nxt %u ack_seq %llu ", |
b589513e6 rds: tcp: compute... |
92 |
rm, rds_tcp_write_seq(tc), |
70041088e RDS: Add TCP tran... |
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
(unsigned long long)rm->m_ack_seq); } if (hdr_off < sizeof(struct rds_header)) { /* see rds_tcp_write_space() */ set_bit(SOCK_NOSPACE, &tc->t_sock->sk->sk_socket->flags); ret = rds_tcp_sendmsg(tc->t_sock, (void *)&rm->m_inc.i_hdr + hdr_off, sizeof(rm->m_inc.i_hdr) - hdr_off); if (ret < 0) goto out; done += ret; if (hdr_off + done != sizeof(struct rds_header)) goto out; } |
76b29ef12 RDS-TCP: Set up M... |
109 |
more = rm->data.op_nents > 1 ? (MSG_MORE | MSG_SENDPAGE_NOTLAST) : 0; |
6c7cc6e46 RDS: Rename data ... |
110 |
while (sg < rm->data.op_nents) { |
76b29ef12 RDS-TCP: Set up M... |
111 |
int flags = MSG_DONTWAIT | MSG_NOSIGNAL | more; |
70041088e RDS: Add TCP tran... |
112 |
ret = tc->t_sock->ops->sendpage(tc->t_sock, |
6c7cc6e46 RDS: Rename data ... |
113 114 115 |
sg_page(&rm->data.op_sg[sg]), rm->data.op_sg[sg].offset + off, rm->data.op_sg[sg].length - off, |
76b29ef12 RDS-TCP: Set up M... |
116 |
flags); |
6c7cc6e46 RDS: Rename data ... |
117 118 119 |
rdsdebug("tcp sendpage %p:%u:%u ret %d ", (void *)sg_page(&rm->data.op_sg[sg]), rm->data.op_sg[sg].offset + off, rm->data.op_sg[sg].length - off, |
70041088e RDS: Add TCP tran... |
120 121 122 123 124 125 |
ret); if (ret <= 0) break; off += ret; done += ret; |
6c7cc6e46 RDS: Rename data ... |
126 |
if (off == rm->data.op_sg[sg].length) { |
70041088e RDS: Add TCP tran... |
127 128 129 |
off = 0; sg++; } |
76b29ef12 RDS-TCP: Set up M... |
130 131 |
if (sg == rm->data.op_nents - 1) more = 0; |
70041088e RDS: Add TCP tran... |
132 133 134 135 136 137 138 139 140 |
} out: if (ret <= 0) { /* write_space will hit after EAGAIN, all else fatal */ if (ret == -EAGAIN) { rds_tcp_stats_inc(s_tcp_sndbuf_full); ret = 0; } else { |
5916e2c15 RDS: TCP: Enable ... |
141 142 143 144 145 |
/* No need to disconnect/reconnect if path_drop * has already been triggered, because, e.g., of * an incoming RST. */ if (rds_conn_path_up(cp)) { |
eee2fa6ab rds: Changing IP ... |
146 |
pr_warn("RDS/tcp: send to %pI6c on cp [%d]" |
5916e2c15 RDS: TCP: Enable ... |
147 148 149 150 |
"returned %d, " "disconnecting and reconnecting ", &conn->c_faddr, cp->cp_index, ret); |
aed20a53a rds: cancel send/... |
151 |
rds_conn_path_drop(cp, false); |
5916e2c15 RDS: TCP: Enable ... |
152 |
} |
70041088e RDS: Add TCP tran... |
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
} } if (done == 0) done = ret; return done; } /* * rm->m_ack_seq is set to the tcp sequence number that corresponds to the * last byte of the message, including the header. This means that the * entire message has been received if rm->m_ack_seq is "before" the next * unacked byte of the TCP sequence space. We have to do very careful * wrapping 32bit comparisons here. */ static int rds_tcp_is_acked(struct rds_message *rm, uint64_t ack) { if (!test_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags)) return 0; return (__s32)((u32)rm->m_ack_seq - (u32)ack) < 0; } void rds_tcp_write_space(struct sock *sk) { void (*write_space)(struct sock *sk); |
ea3b1ea53 RDS: TCP: make ->... |
177 |
struct rds_conn_path *cp; |
70041088e RDS: Add TCP tran... |
178 |
struct rds_tcp_connection *tc; |
38036629c rds: tcp: block B... |
179 |
read_lock_bh(&sk->sk_callback_lock); |
ea3b1ea53 RDS: TCP: make ->... |
180 181 |
cp = sk->sk_user_data; if (!cp) { |
70041088e RDS: Add TCP tran... |
182 183 184 |
write_space = sk->sk_write_space; goto out; } |
ea3b1ea53 RDS: TCP: make ->... |
185 |
tc = cp->cp_transport_data; |
70041088e RDS: Add TCP tran... |
186 187 188 189 190 191 192 193 |
rdsdebug("write_space for tc %p ", tc); write_space = tc->t_orig_write_space; rds_tcp_stats_inc(s_tcp_write_space_calls); rdsdebug("tcp una %u ", rds_tcp_snd_una(tc)); tc->t_last_seen_una = rds_tcp_snd_una(tc); |
ea3b1ea53 RDS: TCP: make ->... |
194 |
rds_send_path_drop_acked(cp, rds_tcp_snd_una(tc), rds_tcp_is_acked); |
70041088e RDS: Add TCP tran... |
195 |
|
3db6e0d17 rds: use RCU to s... |
196 197 |
rcu_read_lock(); if ((refcount_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf && |
ebeeb1ad9 rds: tcp: use rds... |
198 |
!rds_destroy_pending(cp->cp_conn)) |
ea3b1ea53 RDS: TCP: make ->... |
199 |
queue_delayed_work(rds_wq, &cp->cp_send_w, 0); |
3db6e0d17 rds: use RCU to s... |
200 |
rcu_read_unlock(); |
8e82376e5 RDS/TCP: Wait to ... |
201 |
|
70041088e RDS: Add TCP tran... |
202 |
out: |
38036629c rds: tcp: block B... |
203 |
read_unlock_bh(&sk->sk_callback_lock); |
70041088e RDS: Add TCP tran... |
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
/* * write_space is only called when data leaves tcp's send queue if * SOCK_NOSPACE is set. We set SOCK_NOSPACE every time we put * data in tcp's send queue because we use write_space to parse the * sequence numbers and notice that rds messages have been fully * received. * * tcp's write_space clears SOCK_NOSPACE if the send queue has more * than a certain amount of space. So we need to set it again *after* * we call tcp's write_space or else we might only get called on the * first of a series of incoming tcp acks. */ write_space(sk); if (sk->sk_socket) set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); } |