From f1807f5e6388715ab73d98b45d592d11739b6d87 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Mon, 11 Sep 2006 08:24:22 +0300 Subject: [PATCH] IB/sdp: emulate completion with error if packet queued after disconnect. In TCP packet is sent, and we get RST from the remote. Emulate this in SDP. --- drivers/infiniband/ulp/sdp/sdp.h | 1 + drivers/infiniband/ulp/sdp/sdp_bcopy.c | 12 +++++++++--- drivers/infiniband/ulp/sdp/sdp_main.c | 21 +++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/drivers/infiniband/ulp/sdp/sdp.h b/drivers/infiniband/ulp/sdp/sdp.h index 3fd0caf7d726..5476c56aec00 100644 --- a/drivers/infiniband/ulp/sdp/sdp.h +++ b/drivers/infiniband/ulp/sdp/sdp.h @@ -171,6 +171,7 @@ static inline void sdp_set_state(struct sock *sk, int state) extern struct workqueue_struct *sdp_workqueue; int sdp_cma_handler(struct rdma_cm_id *, struct rdma_cm_event *); +void sdp_reset(struct sock *sk); void sdp_reset_sk(struct sock *sk, int rc); void sdp_time_wait_destroy_sk(struct sdp_sock *ssk); void sdp_completion_handler(struct ib_cq *cq, void *cq_context); diff --git a/drivers/infiniband/ulp/sdp/sdp_bcopy.c b/drivers/infiniband/ulp/sdp/sdp_bcopy.c index 4540fa4889fd..ad7c6daf1e9d 100644 --- a/drivers/infiniband/ulp/sdp/sdp_bcopy.c +++ b/drivers/infiniband/ulp/sdp/sdp_bcopy.c @@ -324,8 +324,15 @@ void sdp_post_sends(struct sdp_sock *ssk, int nonagle) struct sk_buff *skb; int c; - if (unlikely(!ssk->id)) + if (unlikely(!ssk->id)) { + if (ssk->isk.sk.sk_send_head) { + sdp_dbg(&ssk->isk.sk, + "Send on socket without cmid ECONNRESET.\n"); + /* TODO: flush send queue? */ + sdp_reset(&ssk->isk.sk); + } return; + } while (ssk->bufs > SDP_MIN_BUFS && ssk->tx_head - ssk->tx_tail < SDP_TX_SIZE && @@ -383,8 +390,7 @@ static void sdp_handle_wc(struct sdp_sock *ssk, struct ib_wc *wc) sdp_dbg(&ssk->isk.sk, "Recv completion with error. " "Status %d\n", wc->status); - sdp_set_error(&ssk->isk.sk, -ECONNRESET); - wake_up(&ssk->wq); + sdp_reset(&ssk->isk.sk); } __kfree_skb(skb); } else { diff --git a/drivers/infiniband/ulp/sdp/sdp_main.c b/drivers/infiniband/ulp/sdp/sdp_main.c index 64e55199af69..20e5f47fc524 100644 --- a/drivers/infiniband/ulp/sdp/sdp_main.c +++ b/drivers/infiniband/ulp/sdp/sdp_main.c @@ -210,6 +210,27 @@ void sdp_reset_sk(struct sock *sk, int rc) sdp_dbg(sk, "%s: destroy in time wait state\n", __func__); sdp_time_wait_destroy_sk(ssk); } + + sk->sk_state_change(sk); +} + +/* Like tcp_reset */ +/* When we get a reset (completion with error) we do this. */ +void sdp_reset(struct sock *sk) +{ + int err; + + if (sk->sk_state != TCP_ESTABLISHED) + return; + + /* We want the right error as BSD sees it (and indeed as we do). */ + + /* On fin we currently only set RCV_SHUTDOWN, so .. */ + err = (sk->sk_shutdown & RCV_SHUTDOWN) ? EPIPE : ECONNRESET; + + sdp_set_error(sk, -err); + wake_up(&sdp_sk(sk)->wq); + sk->sk_state_change(sk); } /* TODO: linger? */ -- 2.50.1