diff options
Diffstat (limited to 'net/rds/ib_recv.c')
-rw-r--r-- | net/rds/ib_recv.c | 53 |
1 files changed, 47 insertions, 6 deletions
diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c index 5709bad28329..cd7a6cfcab03 100644 --- a/net/rds/ib_recv.c +++ b/net/rds/ib_recv.c | |||
@@ -555,6 +555,47 @@ u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic) | |||
555 | return rds_ib_get_ack(ic); | 555 | return rds_ib_get_ack(ic); |
556 | } | 556 | } |
557 | 557 | ||
558 | static struct rds_header *rds_ib_get_header(struct rds_connection *conn, | ||
559 | struct rds_ib_recv_work *recv, | ||
560 | u32 data_len) | ||
561 | { | ||
562 | struct rds_ib_connection *ic = conn->c_transport_data; | ||
563 | void *hdr_buff = &ic->i_recv_hdrs[recv - ic->i_recvs]; | ||
564 | void *addr; | ||
565 | u32 misplaced_hdr_bytes; | ||
566 | |||
567 | /* | ||
568 | * Support header at the front (RDS 3.1+) as well as header-at-end. | ||
569 | * | ||
570 | * Cases: | ||
571 | * 1) header all in header buff (great!) | ||
572 | * 2) header all in data page (copy all to header buff) | ||
573 | * 3) header split across hdr buf + data page | ||
574 | * (move bit in hdr buff to end before copying other bit from data page) | ||
575 | */ | ||
576 | if (conn->c_version > RDS_PROTOCOL_3_0 || data_len == RDS_FRAG_SIZE) | ||
577 | return hdr_buff; | ||
578 | |||
579 | if (data_len <= (RDS_FRAG_SIZE - sizeof(struct rds_header))) { | ||
580 | addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0); | ||
581 | memcpy(hdr_buff, | ||
582 | addr + recv->r_frag->f_offset + data_len, | ||
583 | sizeof(struct rds_header)); | ||
584 | kunmap_atomic(addr, KM_SOFTIRQ0); | ||
585 | return hdr_buff; | ||
586 | } | ||
587 | |||
588 | misplaced_hdr_bytes = (sizeof(struct rds_header) - (RDS_FRAG_SIZE - data_len)); | ||
589 | |||
590 | memmove(hdr_buff + misplaced_hdr_bytes, hdr_buff, misplaced_hdr_bytes); | ||
591 | |||
592 | addr = kmap_atomic(recv->r_frag->f_page, KM_SOFTIRQ0); | ||
593 | memcpy(hdr_buff, addr + recv->r_frag->f_offset + data_len, | ||
594 | sizeof(struct rds_header) - misplaced_hdr_bytes); | ||
595 | kunmap_atomic(addr, KM_SOFTIRQ0); | ||
596 | return hdr_buff; | ||
597 | } | ||
598 | |||
558 | /* | 599 | /* |
559 | * It's kind of lame that we're copying from the posted receive pages into | 600 | * It's kind of lame that we're copying from the posted receive pages into |
560 | * long-lived bitmaps. We could have posted the bitmaps and rdma written into | 601 | * long-lived bitmaps. We could have posted the bitmaps and rdma written into |
@@ -645,7 +686,7 @@ struct rds_ib_ack_state { | |||
645 | }; | 686 | }; |
646 | 687 | ||
647 | static void rds_ib_process_recv(struct rds_connection *conn, | 688 | static void rds_ib_process_recv(struct rds_connection *conn, |
648 | struct rds_ib_recv_work *recv, u32 byte_len, | 689 | struct rds_ib_recv_work *recv, u32 data_len, |
649 | struct rds_ib_ack_state *state) | 690 | struct rds_ib_ack_state *state) |
650 | { | 691 | { |
651 | struct rds_ib_connection *ic = conn->c_transport_data; | 692 | struct rds_ib_connection *ic = conn->c_transport_data; |
@@ -655,9 +696,9 @@ static void rds_ib_process_recv(struct rds_connection *conn, | |||
655 | /* XXX shut down the connection if port 0,0 are seen? */ | 696 | /* XXX shut down the connection if port 0,0 are seen? */ |
656 | 697 | ||
657 | rdsdebug("ic %p ibinc %p recv %p byte len %u\n", ic, ibinc, recv, | 698 | rdsdebug("ic %p ibinc %p recv %p byte len %u\n", ic, ibinc, recv, |
658 | byte_len); | 699 | data_len); |
659 | 700 | ||
660 | if (byte_len < sizeof(struct rds_header)) { | 701 | if (data_len < sizeof(struct rds_header)) { |
661 | rds_ib_conn_error(conn, "incoming message " | 702 | rds_ib_conn_error(conn, "incoming message " |
662 | "from %pI4 didn't inclue a " | 703 | "from %pI4 didn't inclue a " |
663 | "header, disconnecting and " | 704 | "header, disconnecting and " |
@@ -665,9 +706,9 @@ static void rds_ib_process_recv(struct rds_connection *conn, | |||
665 | &conn->c_faddr); | 706 | &conn->c_faddr); |
666 | return; | 707 | return; |
667 | } | 708 | } |
668 | byte_len -= sizeof(struct rds_header); | 709 | data_len -= sizeof(struct rds_header); |
669 | 710 | ||
670 | ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs]; | 711 | ihdr = rds_ib_get_header(conn, recv, data_len); |
671 | 712 | ||
672 | /* Validate the checksum. */ | 713 | /* Validate the checksum. */ |
673 | if (!rds_message_verify_checksum(ihdr)) { | 714 | if (!rds_message_verify_checksum(ihdr)) { |
@@ -687,7 +728,7 @@ static void rds_ib_process_recv(struct rds_connection *conn, | |||
687 | if (ihdr->h_credit) | 728 | if (ihdr->h_credit) |
688 | rds_ib_send_add_credits(conn, ihdr->h_credit); | 729 | rds_ib_send_add_credits(conn, ihdr->h_credit); |
689 | 730 | ||
690 | if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) { | 731 | if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && data_len == 0) { |
691 | /* This is an ACK-only packet. The fact that it gets | 732 | /* This is an ACK-only packet. The fact that it gets |
692 | * special treatment here is that historically, ACKs | 733 | * special treatment here is that historically, ACKs |
693 | * were rather special beasts. | 734 | * were rather special beasts. |