Blame view
net/rds/tcp_send.c
6.34 KB
70041088e RDS: Add TCP tran... |
1 2 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 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
/* * Copyright (c) 2006 Oracle. All rights reserved. * * 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> #include "rds.h" #include "tcp.h" static void rds_tcp_cork(struct socket *sock, int val) { mm_segment_t oldfs; oldfs = get_fs(); set_fs(KERNEL_DS); sock->ops->setsockopt(sock, SOL_TCP, TCP_CORK, (char __user *)&val, sizeof(val)); set_fs(oldfs); } void rds_tcp_xmit_prepare(struct rds_connection *conn) { struct rds_tcp_connection *tc = conn->c_transport_data; rds_tcp_cork(tc->t_sock, 1); } void rds_tcp_xmit_complete(struct rds_connection *conn) { struct rds_tcp_connection *tc = conn->c_transport_data; rds_tcp_cork(tc->t_sock, 0); } /* the core send_sem serializes this with other xmit and shutdown */ |
ff51bf841 rds: make local f... |
66 |
static int rds_tcp_sendmsg(struct socket *sock, void *data, unsigned int len) |
70041088e RDS: Add TCP tran... |
67 68 69 70 71 72 73 74 75 76 77 78 79 |
{ struct kvec vec = { .iov_base = data, .iov_len = len, }; struct msghdr msg = { .msg_flags = MSG_DONTWAIT | MSG_NOSIGNAL, }; 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... |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
int rds_tcp_xmit(struct rds_connection *conn, struct rds_message *rm, unsigned int hdr_off, unsigned int sg, unsigned int off) { struct rds_tcp_connection *tc = conn->c_transport_data; int done = 0; int ret = 0; 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(). */ tc->t_last_sent_nxt = rds_tcp_snd_nxt(tc); rm->m_ack_seq = tc->t_last_sent_nxt + sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len) - 1; smp_mb__before_clear_bit(); set_bit(RDS_MSG_HAS_ACK_SEQ, &rm->m_flags); tc->t_last_expected_una = rm->m_ack_seq + 1; rdsdebug("rm %p tcp nxt %u ack_seq %llu ", rm, rds_tcp_snd_nxt(tc), (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; } |
6c7cc6e46 RDS: Rename data ... |
119 |
while (sg < rm->data.op_nents) { |
70041088e RDS: Add TCP tran... |
120 |
ret = tc->t_sock->ops->sendpage(tc->t_sock, |
6c7cc6e46 RDS: Rename data ... |
121 122 123 |
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... |
124 |
MSG_DONTWAIT|MSG_NOSIGNAL); |
6c7cc6e46 RDS: Rename data ... |
125 126 127 |
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... |
128 129 130 131 132 133 |
ret); if (ret <= 0) break; off += ret; done += ret; |
6c7cc6e46 RDS: Rename data ... |
134 |
if (off == rm->data.op_sg[sg].length) { |
70041088e RDS: Add TCP tran... |
135 136 137 138 139 140 141 142 143 144 145 146 |
off = 0; sg++; } } 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 { |
6884b348e net/rds: remove u... |
147 |
printk(KERN_WARNING "RDS/tcp: send to %pI4 " |
70041088e RDS: Add TCP tran... |
148 149 |
"returned %d, disconnecting and reconnecting ", |
6884b348e net/rds: remove u... |
150 |
&conn->c_faddr, ret); |
70041088e RDS: Add TCP tran... |
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
rds_conn_drop(conn); } } 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); struct rds_connection *conn; struct rds_tcp_connection *tc; |
bfdc587c5 rds: Don't disabl... |
178 |
read_lock(&sk->sk_callback_lock); |
70041088e RDS: Add TCP tran... |
179 |
conn = sk->sk_user_data; |
8690bfa17 RDS: cleanup: rem... |
180 |
if (!conn) { |
70041088e RDS: Add TCP tran... |
181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
write_space = sk->sk_write_space; goto out; } tc = conn->c_transport_data; 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); rds_send_drop_acked(conn, rds_tcp_snd_una(tc), rds_tcp_is_acked); |
8e82376e5 RDS/TCP: Wait to ... |
195 196 |
if ((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) queue_delayed_work(rds_wq, &conn->c_send_w, 0); |
70041088e RDS: Add TCP tran... |
197 |
out: |
bfdc587c5 rds: Don't disabl... |
198 |
read_unlock(&sk->sk_callback_lock); |
70041088e RDS: Add TCP tran... |
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
/* * 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); } |