diff options
Diffstat (limited to 'net/rxrpc/recvmsg.c')
-rw-r--r-- | net/rxrpc/recvmsg.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c index 1edf2cf62cc5..8b8d7e14f800 100644 --- a/net/rxrpc/recvmsg.c +++ b/net/rxrpc/recvmsg.c | |||
@@ -134,6 +134,8 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call) | |||
134 | { | 134 | { |
135 | _enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]); | 135 | _enter("%d,%s", call->debug_id, rxrpc_call_states[call->state]); |
136 | 136 | ||
137 | ASSERTCMP(call->rx_hard_ack, ==, call->rx_top); | ||
138 | |||
137 | if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) { | 139 | if (call->state == RXRPC_CALL_CLIENT_RECV_REPLY) { |
138 | rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, 0, true, false); | 140 | rxrpc_propose_ACK(call, RXRPC_ACK_IDLE, 0, 0, true, false); |
139 | rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ACK); | 141 | rxrpc_send_call_packet(call, RXRPC_PACKET_TYPE_ACK); |
@@ -163,8 +165,10 @@ static void rxrpc_end_rx_phase(struct rxrpc_call *call) | |||
163 | */ | 165 | */ |
164 | static void rxrpc_rotate_rx_window(struct rxrpc_call *call) | 166 | static void rxrpc_rotate_rx_window(struct rxrpc_call *call) |
165 | { | 167 | { |
168 | struct rxrpc_skb_priv *sp; | ||
166 | struct sk_buff *skb; | 169 | struct sk_buff *skb; |
167 | rxrpc_seq_t hard_ack, top; | 170 | rxrpc_seq_t hard_ack, top; |
171 | u8 flags; | ||
168 | int ix; | 172 | int ix; |
169 | 173 | ||
170 | _enter("%d", call->debug_id); | 174 | _enter("%d", call->debug_id); |
@@ -177,6 +181,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) | |||
177 | ix = hard_ack & RXRPC_RXTX_BUFF_MASK; | 181 | ix = hard_ack & RXRPC_RXTX_BUFF_MASK; |
178 | skb = call->rxtx_buffer[ix]; | 182 | skb = call->rxtx_buffer[ix]; |
179 | rxrpc_see_skb(skb); | 183 | rxrpc_see_skb(skb); |
184 | sp = rxrpc_skb(skb); | ||
185 | flags = sp->hdr.flags; | ||
180 | call->rxtx_buffer[ix] = NULL; | 186 | call->rxtx_buffer[ix] = NULL; |
181 | call->rxtx_annotations[ix] = 0; | 187 | call->rxtx_annotations[ix] = 0; |
182 | /* Barrier against rxrpc_input_data(). */ | 188 | /* Barrier against rxrpc_input_data(). */ |
@@ -184,8 +190,8 @@ static void rxrpc_rotate_rx_window(struct rxrpc_call *call) | |||
184 | 190 | ||
185 | rxrpc_free_skb(skb); | 191 | rxrpc_free_skb(skb); |
186 | 192 | ||
187 | _debug("%u,%u,%lx", hard_ack, top, call->flags); | 193 | _debug("%u,%u,%02x", hard_ack, top, flags); |
188 | if (hard_ack == top && test_bit(RXRPC_CALL_RX_LAST, &call->flags)) | 194 | if (flags & RXRPC_LAST_PACKET) |
189 | rxrpc_end_rx_phase(call); | 195 | rxrpc_end_rx_phase(call); |
190 | } | 196 | } |
191 | 197 | ||
@@ -278,13 +284,19 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |||
278 | size_t remain; | 284 | size_t remain; |
279 | bool last; | 285 | bool last; |
280 | unsigned int rx_pkt_offset, rx_pkt_len; | 286 | unsigned int rx_pkt_offset, rx_pkt_len; |
281 | int ix, copy, ret = 0; | 287 | int ix, copy, ret = -EAGAIN, ret2; |
282 | 288 | ||
283 | _enter(""); | 289 | _enter(""); |
284 | 290 | ||
285 | rx_pkt_offset = call->rx_pkt_offset; | 291 | rx_pkt_offset = call->rx_pkt_offset; |
286 | rx_pkt_len = call->rx_pkt_len; | 292 | rx_pkt_len = call->rx_pkt_len; |
287 | 293 | ||
294 | if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) { | ||
295 | seq = call->rx_hard_ack; | ||
296 | ret = 1; | ||
297 | goto done; | ||
298 | } | ||
299 | |||
288 | /* Barriers against rxrpc_input_data(). */ | 300 | /* Barriers against rxrpc_input_data(). */ |
289 | hard_ack = call->rx_hard_ack; | 301 | hard_ack = call->rx_hard_ack; |
290 | top = smp_load_acquire(&call->rx_top); | 302 | top = smp_load_acquire(&call->rx_top); |
@@ -301,11 +313,13 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |||
301 | sock_recv_timestamp(msg, sock->sk, skb); | 313 | sock_recv_timestamp(msg, sock->sk, skb); |
302 | 314 | ||
303 | if (rx_pkt_offset == 0) { | 315 | if (rx_pkt_offset == 0) { |
304 | ret = rxrpc_locate_data(call, skb, | 316 | ret2 = rxrpc_locate_data(call, skb, |
305 | &call->rxtx_annotations[ix], | 317 | &call->rxtx_annotations[ix], |
306 | &rx_pkt_offset, &rx_pkt_len); | 318 | &rx_pkt_offset, &rx_pkt_len); |
307 | if (ret < 0) | 319 | if (ret2 < 0) { |
320 | ret = ret2; | ||
308 | goto out; | 321 | goto out; |
322 | } | ||
309 | } | 323 | } |
310 | _debug("recvmsg %x DATA #%u { %d, %d }", | 324 | _debug("recvmsg %x DATA #%u { %d, %d }", |
311 | sp->hdr.callNumber, seq, rx_pkt_offset, rx_pkt_len); | 325 | sp->hdr.callNumber, seq, rx_pkt_offset, rx_pkt_len); |
@@ -316,10 +330,12 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |||
316 | if (copy > remain) | 330 | if (copy > remain) |
317 | copy = remain; | 331 | copy = remain; |
318 | if (copy > 0) { | 332 | if (copy > 0) { |
319 | ret = skb_copy_datagram_iter(skb, rx_pkt_offset, iter, | 333 | ret2 = skb_copy_datagram_iter(skb, rx_pkt_offset, iter, |
320 | copy); | 334 | copy); |
321 | if (ret < 0) | 335 | if (ret2 < 0) { |
336 | ret = ret2; | ||
322 | goto out; | 337 | goto out; |
338 | } | ||
323 | 339 | ||
324 | /* handle piecemeal consumption of data packets */ | 340 | /* handle piecemeal consumption of data packets */ |
325 | _debug("copied %d @%zu", copy, *_offset); | 341 | _debug("copied %d @%zu", copy, *_offset); |
@@ -332,6 +348,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |||
332 | if (rx_pkt_len > 0) { | 348 | if (rx_pkt_len > 0) { |
333 | _debug("buffer full"); | 349 | _debug("buffer full"); |
334 | ASSERTCMP(*_offset, ==, len); | 350 | ASSERTCMP(*_offset, ==, len); |
351 | ret = 0; | ||
335 | break; | 352 | break; |
336 | } | 353 | } |
337 | 354 | ||
@@ -342,19 +359,19 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call, | |||
342 | rx_pkt_offset = 0; | 359 | rx_pkt_offset = 0; |
343 | rx_pkt_len = 0; | 360 | rx_pkt_len = 0; |
344 | 361 | ||
345 | ASSERTIFCMP(last, seq, ==, top); | 362 | if (last) { |
346 | } | 363 | ASSERTCMP(seq, ==, READ_ONCE(call->rx_top)); |
347 | |||
348 | if (after(seq, top)) { | ||
349 | ret = -EAGAIN; | ||
350 | if (test_bit(RXRPC_CALL_RX_LAST, &call->flags)) | ||
351 | ret = 1; | 364 | ret = 1; |
365 | goto out; | ||
366 | } | ||
352 | } | 367 | } |
368 | |||
353 | out: | 369 | out: |
354 | if (!(flags & MSG_PEEK)) { | 370 | if (!(flags & MSG_PEEK)) { |
355 | call->rx_pkt_offset = rx_pkt_offset; | 371 | call->rx_pkt_offset = rx_pkt_offset; |
356 | call->rx_pkt_len = rx_pkt_len; | 372 | call->rx_pkt_len = rx_pkt_len; |
357 | } | 373 | } |
374 | done: | ||
358 | _leave(" = %d [%u/%u]", ret, seq, top); | 375 | _leave(" = %d [%u/%u]", ret, seq, top); |
359 | return ret; | 376 | return ret; |
360 | } | 377 | } |