diff options
Diffstat (limited to 'net/rds/iw_recv.c')
-rw-r--r-- | net/rds/iw_recv.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c index 8683f5f66c4b..54af7d6b92da 100644 --- a/net/rds/iw_recv.c +++ b/net/rds/iw_recv.c | |||
@@ -143,15 +143,16 @@ static int rds_iw_recv_refill_one(struct rds_connection *conn, | |||
143 | int ret = -ENOMEM; | 143 | int ret = -ENOMEM; |
144 | 144 | ||
145 | if (recv->r_iwinc == NULL) { | 145 | if (recv->r_iwinc == NULL) { |
146 | if (atomic_read(&rds_iw_allocation) >= rds_iw_sysctl_max_recv_allocation) { | 146 | if (!atomic_add_unless(&rds_iw_allocation, 1, rds_iw_sysctl_max_recv_allocation)) { |
147 | rds_iw_stats_inc(s_iw_rx_alloc_limit); | 147 | rds_iw_stats_inc(s_iw_rx_alloc_limit); |
148 | goto out; | 148 | goto out; |
149 | } | 149 | } |
150 | recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab, | 150 | recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab, |
151 | kptr_gfp); | 151 | kptr_gfp); |
152 | if (recv->r_iwinc == NULL) | 152 | if (recv->r_iwinc == NULL) { |
153 | atomic_dec(&rds_iw_allocation); | ||
153 | goto out; | 154 | goto out; |
154 | atomic_inc(&rds_iw_allocation); | 155 | } |
155 | INIT_LIST_HEAD(&recv->r_iwinc->ii_frags); | 156 | INIT_LIST_HEAD(&recv->r_iwinc->ii_frags); |
156 | rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr); | 157 | rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr); |
157 | } | 158 | } |
@@ -229,8 +230,8 @@ int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp, | |||
229 | int ret = 0; | 230 | int ret = 0; |
230 | u32 pos; | 231 | u32 pos; |
231 | 232 | ||
232 | while ((prefill || rds_conn_up(conn)) | 233 | while ((prefill || rds_conn_up(conn)) && |
233 | && rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) { | 234 | rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) { |
234 | if (pos >= ic->i_recv_ring.w_nr) { | 235 | if (pos >= ic->i_recv_ring.w_nr) { |
235 | printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n", | 236 | printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n", |
236 | pos); | 237 | pos); |
@@ -729,10 +730,10 @@ static void rds_iw_process_recv(struct rds_connection *conn, | |||
729 | hdr = &iwinc->ii_inc.i_hdr; | 730 | hdr = &iwinc->ii_inc.i_hdr; |
730 | /* We can't just use memcmp here; fragments of a | 731 | /* We can't just use memcmp here; fragments of a |
731 | * single message may carry different ACKs */ | 732 | * single message may carry different ACKs */ |
732 | if (hdr->h_sequence != ihdr->h_sequence | 733 | if (hdr->h_sequence != ihdr->h_sequence || |
733 | || hdr->h_len != ihdr->h_len | 734 | hdr->h_len != ihdr->h_len || |
734 | || hdr->h_sport != ihdr->h_sport | 735 | hdr->h_sport != ihdr->h_sport || |
735 | || hdr->h_dport != ihdr->h_dport) { | 736 | hdr->h_dport != ihdr->h_dport) { |
736 | rds_iw_conn_error(conn, | 737 | rds_iw_conn_error(conn, |
737 | "fragment header mismatch; forcing reconnect\n"); | 738 | "fragment header mismatch; forcing reconnect\n"); |
738 | return; | 739 | return; |
@@ -783,17 +784,22 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) | |||
783 | { | 784 | { |
784 | struct rds_connection *conn = context; | 785 | struct rds_connection *conn = context; |
785 | struct rds_iw_connection *ic = conn->c_transport_data; | 786 | struct rds_iw_connection *ic = conn->c_transport_data; |
786 | struct ib_wc wc; | ||
787 | struct rds_iw_ack_state state = { 0, }; | ||
788 | struct rds_iw_recv_work *recv; | ||
789 | 787 | ||
790 | rdsdebug("conn %p cq %p\n", conn, cq); | 788 | rdsdebug("conn %p cq %p\n", conn, cq); |
791 | 789 | ||
792 | rds_iw_stats_inc(s_iw_rx_cq_call); | 790 | rds_iw_stats_inc(s_iw_rx_cq_call); |
793 | 791 | ||
794 | ib_req_notify_cq(cq, IB_CQ_SOLICITED); | 792 | tasklet_schedule(&ic->i_recv_tasklet); |
793 | } | ||
794 | |||
795 | static inline void rds_poll_cq(struct rds_iw_connection *ic, | ||
796 | struct rds_iw_ack_state *state) | ||
797 | { | ||
798 | struct rds_connection *conn = ic->conn; | ||
799 | struct ib_wc wc; | ||
800 | struct rds_iw_recv_work *recv; | ||
795 | 801 | ||
796 | while (ib_poll_cq(cq, 1, &wc) > 0) { | 802 | while (ib_poll_cq(ic->i_recv_cq, 1, &wc) > 0) { |
797 | rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n", | 803 | rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n", |
798 | (unsigned long long)wc.wr_id, wc.status, wc.byte_len, | 804 | (unsigned long long)wc.wr_id, wc.status, wc.byte_len, |
799 | be32_to_cpu(wc.ex.imm_data)); | 805 | be32_to_cpu(wc.ex.imm_data)); |
@@ -811,7 +817,7 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) | |||
811 | if (rds_conn_up(conn) || rds_conn_connecting(conn)) { | 817 | if (rds_conn_up(conn) || rds_conn_connecting(conn)) { |
812 | /* We expect errors as the qp is drained during shutdown */ | 818 | /* We expect errors as the qp is drained during shutdown */ |
813 | if (wc.status == IB_WC_SUCCESS) { | 819 | if (wc.status == IB_WC_SUCCESS) { |
814 | rds_iw_process_recv(conn, recv, wc.byte_len, &state); | 820 | rds_iw_process_recv(conn, recv, wc.byte_len, state); |
815 | } else { | 821 | } else { |
816 | rds_iw_conn_error(conn, "recv completion on " | 822 | rds_iw_conn_error(conn, "recv completion on " |
817 | "%pI4 had status %u, disconnecting and " | 823 | "%pI4 had status %u, disconnecting and " |
@@ -822,6 +828,17 @@ void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context) | |||
822 | 828 | ||
823 | rds_iw_ring_free(&ic->i_recv_ring, 1); | 829 | rds_iw_ring_free(&ic->i_recv_ring, 1); |
824 | } | 830 | } |
831 | } | ||
832 | |||
833 | void rds_iw_recv_tasklet_fn(unsigned long data) | ||
834 | { | ||
835 | struct rds_iw_connection *ic = (struct rds_iw_connection *) data; | ||
836 | struct rds_connection *conn = ic->conn; | ||
837 | struct rds_iw_ack_state state = { 0, }; | ||
838 | |||
839 | rds_poll_cq(ic, &state); | ||
840 | ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED); | ||
841 | rds_poll_cq(ic, &state); | ||
825 | 842 | ||
826 | if (state.ack_next_valid) | 843 | if (state.ack_next_valid) |
827 | rds_iw_set_ack(ic, state.ack_next, state.ack_required); | 844 | rds_iw_set_ack(ic, state.ack_next, state.ack_required); |