summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2019-10-31 08:13:46 -0400
committerDavid S. Miller <davem@davemloft.net>2019-10-31 15:23:09 -0400
commitf9c32435ab7221d1d6cb35738fa85a2da012b23e (patch)
treeaba8c4e4ecddcd677e1e77d1d64464c499b17365
parent5a7ec66782fc2d952b355696114104cc828d6440 (diff)
rxrpc: Fix handling of last subpacket of jumbo packet
When rxrpc_recvmsg_data() sets the return value to 1 because it's drained all the data for the last packet, it checks the last-packet flag on the whole packet - but this is wrong, since the last-packet flag is only set on the final subpacket of the last jumbo packet. This means that a call that receives its last packet in a jumbo packet won't complete properly. Fix this by having rxrpc_locate_data() determine the last-packet state of the subpacket it's looking at and passing that back to the caller rather than having the caller look in the packet header. The caller then needs to cache this in the rxrpc_call struct as rxrpc_locate_data() isn't then called again for this packet. Fixes: 248f219cb8bc ("rxrpc: Rewrite the data and ack handling code") Fixes: e2de6c404898 ("rxrpc: Use info in skbuff instead of reparsing a jumbo packet") Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/rxrpc/ar-internal.h1
-rw-r--r--net/rxrpc/recvmsg.c18
2 files changed, 14 insertions, 5 deletions
diff --git a/net/rxrpc/ar-internal.h b/net/rxrpc/ar-internal.h
index ecc17dabec8f..7c7d10f2e0c1 100644
--- a/net/rxrpc/ar-internal.h
+++ b/net/rxrpc/ar-internal.h
@@ -601,6 +601,7 @@ struct rxrpc_call {
601 int debug_id; /* debug ID for printks */ 601 int debug_id; /* debug ID for printks */
602 unsigned short rx_pkt_offset; /* Current recvmsg packet offset */ 602 unsigned short rx_pkt_offset; /* Current recvmsg packet offset */
603 unsigned short rx_pkt_len; /* Current recvmsg packet len */ 603 unsigned short rx_pkt_len; /* Current recvmsg packet len */
604 bool rx_pkt_last; /* Current recvmsg packet is last */
604 605
605 /* Rx/Tx circular buffer, depending on phase. 606 /* Rx/Tx circular buffer, depending on phase.
606 * 607 *
diff --git a/net/rxrpc/recvmsg.c b/net/rxrpc/recvmsg.c
index a4090797c9b2..8578c39ec839 100644
--- a/net/rxrpc/recvmsg.c
+++ b/net/rxrpc/recvmsg.c
@@ -267,11 +267,13 @@ static int rxrpc_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
267 */ 267 */
268static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb, 268static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
269 u8 *_annotation, 269 u8 *_annotation,
270 unsigned int *_offset, unsigned int *_len) 270 unsigned int *_offset, unsigned int *_len,
271 bool *_last)
271{ 272{
272 struct rxrpc_skb_priv *sp = rxrpc_skb(skb); 273 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
273 unsigned int offset = sizeof(struct rxrpc_wire_header); 274 unsigned int offset = sizeof(struct rxrpc_wire_header);
274 unsigned int len; 275 unsigned int len;
276 bool last = false;
275 int ret; 277 int ret;
276 u8 annotation = *_annotation; 278 u8 annotation = *_annotation;
277 u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET; 279 u8 subpacket = annotation & RXRPC_RX_ANNO_SUBPACKET;
@@ -281,6 +283,8 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
281 len = skb->len - offset; 283 len = skb->len - offset;
282 if (subpacket < sp->nr_subpackets - 1) 284 if (subpacket < sp->nr_subpackets - 1)
283 len = RXRPC_JUMBO_DATALEN; 285 len = RXRPC_JUMBO_DATALEN;
286 else if (sp->rx_flags & RXRPC_SKB_INCL_LAST)
287 last = true;
284 288
285 if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) { 289 if (!(annotation & RXRPC_RX_ANNO_VERIFIED)) {
286 ret = rxrpc_verify_packet(call, skb, annotation, offset, len); 290 ret = rxrpc_verify_packet(call, skb, annotation, offset, len);
@@ -291,6 +295,7 @@ static int rxrpc_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
291 295
292 *_offset = offset; 296 *_offset = offset;
293 *_len = len; 297 *_len = len;
298 *_last = last;
294 call->security->locate_data(call, skb, _offset, _len); 299 call->security->locate_data(call, skb, _offset, _len);
295 return 0; 300 return 0;
296} 301}
@@ -309,7 +314,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
309 rxrpc_serial_t serial; 314 rxrpc_serial_t serial;
310 rxrpc_seq_t hard_ack, top, seq; 315 rxrpc_seq_t hard_ack, top, seq;
311 size_t remain; 316 size_t remain;
312 bool last; 317 bool rx_pkt_last;
313 unsigned int rx_pkt_offset, rx_pkt_len; 318 unsigned int rx_pkt_offset, rx_pkt_len;
314 int ix, copy, ret = -EAGAIN, ret2; 319 int ix, copy, ret = -EAGAIN, ret2;
315 320
@@ -319,6 +324,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
319 324
320 rx_pkt_offset = call->rx_pkt_offset; 325 rx_pkt_offset = call->rx_pkt_offset;
321 rx_pkt_len = call->rx_pkt_len; 326 rx_pkt_len = call->rx_pkt_len;
327 rx_pkt_last = call->rx_pkt_last;
322 328
323 if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) { 329 if (call->state >= RXRPC_CALL_SERVER_ACK_REQUEST) {
324 seq = call->rx_hard_ack; 330 seq = call->rx_hard_ack;
@@ -329,6 +335,7 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
329 /* Barriers against rxrpc_input_data(). */ 335 /* Barriers against rxrpc_input_data(). */
330 hard_ack = call->rx_hard_ack; 336 hard_ack = call->rx_hard_ack;
331 seq = hard_ack + 1; 337 seq = hard_ack + 1;
338
332 while (top = smp_load_acquire(&call->rx_top), 339 while (top = smp_load_acquire(&call->rx_top),
333 before_eq(seq, top) 340 before_eq(seq, top)
334 ) { 341 ) {
@@ -356,7 +363,8 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
356 if (rx_pkt_offset == 0) { 363 if (rx_pkt_offset == 0) {
357 ret2 = rxrpc_locate_data(call, skb, 364 ret2 = rxrpc_locate_data(call, skb,
358 &call->rxtx_annotations[ix], 365 &call->rxtx_annotations[ix],
359 &rx_pkt_offset, &rx_pkt_len); 366 &rx_pkt_offset, &rx_pkt_len,
367 &rx_pkt_last);
360 trace_rxrpc_recvmsg(call, rxrpc_recvmsg_next, seq, 368 trace_rxrpc_recvmsg(call, rxrpc_recvmsg_next, seq,
361 rx_pkt_offset, rx_pkt_len, ret2); 369 rx_pkt_offset, rx_pkt_len, ret2);
362 if (ret2 < 0) { 370 if (ret2 < 0) {
@@ -396,13 +404,12 @@ static int rxrpc_recvmsg_data(struct socket *sock, struct rxrpc_call *call,
396 } 404 }
397 405
398 /* The whole packet has been transferred. */ 406 /* The whole packet has been transferred. */
399 last = sp->hdr.flags & RXRPC_LAST_PACKET;
400 if (!(flags & MSG_PEEK)) 407 if (!(flags & MSG_PEEK))
401 rxrpc_rotate_rx_window(call); 408 rxrpc_rotate_rx_window(call);
402 rx_pkt_offset = 0; 409 rx_pkt_offset = 0;
403 rx_pkt_len = 0; 410 rx_pkt_len = 0;
404 411
405 if (last) { 412 if (rx_pkt_last) {
406 ASSERTCMP(seq, ==, READ_ONCE(call->rx_top)); 413 ASSERTCMP(seq, ==, READ_ONCE(call->rx_top));
407 ret = 1; 414 ret = 1;
408 goto out; 415 goto out;
@@ -415,6 +422,7 @@ out:
415 if (!(flags & MSG_PEEK)) { 422 if (!(flags & MSG_PEEK)) {
416 call->rx_pkt_offset = rx_pkt_offset; 423 call->rx_pkt_offset = rx_pkt_offset;
417 call->rx_pkt_len = rx_pkt_len; 424 call->rx_pkt_len = rx_pkt_len;
425 call->rx_pkt_last = rx_pkt_last;
418 } 426 }
419done: 427done:
420 trace_rxrpc_recvmsg(call, rxrpc_recvmsg_data_return, seq, 428 trace_rxrpc_recvmsg(call, rxrpc_recvmsg_data_return, seq,