[ofa-general] error with ibv_poll_cq() call
Roland Dreier
rdreier at cisco.com
Fri Mar 28 22:35:19 PDT 2008
> It looks like we have a race condition in mlx4_destroy_qp. We clean the
> cq BEFORE modifying the QP to reset (done in kernel as part of
> the ibv_cmd_destroy_qp() flow).
ouch, you're right. however I think your patch is not the best way to
handle this:
> - mlx4_cq_clean(to_mcq(ibqp->recv_cq), ibqp->qp_num,
> - ibqp->srq ? to_msrq(ibqp->srq) : NULL);
> - if (ibqp->send_cq != ibqp->recv_cq)
> - mlx4_cq_clean(to_mcq(ibqp->send_cq), ibqp->qp_num, NULL);
> -
> mlx4_lock_cqs(ibqp);
> mlx4_clear_qp(to_mctx(ibqp->context), ibqp->qp_num);
> mlx4_unlock_cqs(ibqp);
> @@ -576,6 +571,11 @@ int mlx4_destroy_qp(struct ibv_qp *ibqp)
> return ret;
> }
>
> + mlx4_cq_clean(to_mcq(ibqp->recv_cq), ibqp->qp_num,
> + ibqp->srq ? to_msrq(ibqp->srq) : NULL);
> + if (ibqp->send_cq != ibqp->recv_cq)
> + mlx4_cq_clean(to_mcq(ibqp->send_cq), ibqp->qp_num, NULL);
> +
because you leave the clear_qp call before the cq_clean and they are
not within the same cq lock, there is a window where a consumer could
poll a valid CQE for a qp that is no longer in the table. I think
it's better to really match the logic of the kernel driver (which I
think is correct).
untested patch below:
diff --git a/src/cq.c b/src/cq.c
index 91297e4..53c6e06 100644
--- a/src/cq.c
+++ b/src/cq.c
@@ -381,15 +381,13 @@ void mlx4_cq_event(struct ibv_cq *cq)
to_mcq(cq)->arm_sn++;
}
-void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq)
+void __mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq)
{
struct mlx4_cqe *cqe, *dest;
uint32_t prod_index;
uint8_t owner_bit;
int nfreed = 0;
- pthread_spin_lock(&cq->lock);
-
/*
* First we need to find the current producer index, so we
* know where to start cleaning from. It doesn't matter if HW
@@ -429,7 +427,12 @@ void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq)
wmb();
update_cons_index(cq);
}
+}
+void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq)
+{
+ pthread_spin_lock(&cq->lock);
+ __mlx4_cq_clean(cq, qpn, srq);
pthread_spin_unlock(&cq->lock);
}
diff --git a/src/mlx4.h b/src/mlx4.h
index 3710a17..9b0ad6a 100644
--- a/src/mlx4.h
+++ b/src/mlx4.h
@@ -312,8 +312,8 @@ int mlx4_destroy_cq(struct ibv_cq *cq);
int mlx4_poll_cq(struct ibv_cq *cq, int ne, struct ibv_wc *wc);
int mlx4_arm_cq(struct ibv_cq *cq, int solicited);
void mlx4_cq_event(struct ibv_cq *cq);
-void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn,
- struct mlx4_srq *srq);
+__void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq);
+void mlx4_cq_clean(struct mlx4_cq *cq, uint32_t qpn, struct mlx4_srq *srq);
void mlx4_cq_resize_copy_cqes(struct mlx4_cq *cq, void *buf, int new_cqe);
struct ibv_srq *mlx4_create_srq(struct ibv_pd *pd,
diff --git a/src/verbs.c b/src/verbs.c
index 50e0947..26174f8 100644
--- a/src/verbs.c
+++ b/src/verbs.c
@@ -532,23 +532,20 @@ int mlx4_destroy_qp(struct ibv_qp *ibqp)
struct mlx4_qp *qp = to_mqp(ibqp);
int ret;
- mlx4_cq_clean(to_mcq(ibqp->recv_cq), ibqp->qp_num,
- ibqp->srq ? to_msrq(ibqp->srq) : NULL);
- if (ibqp->send_cq != ibqp->recv_cq)
- mlx4_cq_clean(to_mcq(ibqp->send_cq), ibqp->qp_num, NULL);
+ ret = ibv_cmd_destroy_qp(ibqp);
+ if (ret)
+ return ret;
mlx4_lock_cqs(ibqp);
- mlx4_clear_qp(to_mctx(ibqp->context), ibqp->qp_num);
- mlx4_unlock_cqs(ibqp);
- ret = ibv_cmd_destroy_qp(ibqp);
- if (ret) {
- mlx4_lock_cqs(ibqp);
- mlx4_store_qp(to_mctx(ibqp->context), ibqp->qp_num, qp);
- mlx4_unlock_cqs(ibqp);
+ __mlx4_cq_clean(to_mcq(ibqp->recv_cq), ibqp->qp_num,
+ ibqp->srq ? to_msrq(ibqp->srq) : NULL);
+ if (ibqp->send_cq != ibqp->recv_cq)
+ __mlx4_cq_clean(to_mcq(ibqp->send_cq), ibqp->qp_num, NULL);
- return ret;
- }
+ mlx4_clear_qp(to_mctx(ibqp->context), ibqp->qp_num);
+
+ mlx4_unlock_cqs(ibqp);
if (!ibqp->srq)
mlx4_free_db(to_mctx(ibqp->context), MLX4_DB_TYPE_RQ, qp->db);
More information about the general
mailing list