> ib_send_cm_sidr_rep could sometimes erase the node from the sidr > (depending on errors in the process). Since ib_send_cm_sidr_rep is > called both from cm_sidr_req_handler and cm_destroy_id, cm_id_priv
This should clarify that it is the app calling from the callback, and not a direct call from the cm_sidr_req_handler. > could be either erased from the rb_tree twice or not erased at all. In an error case, I can see why it would be left in the rbtree, but I don't see how it can be removed twice. > Fixing that by making sure it's erased only once before freeing > cm_id_priv. > > Fixes: a977049dacde ('[PATCH] IB: Add the kernel CM implementation') > Signed-off-by: Doron Tsur <dor...@mellanox.com> > Signed-off-by: Matan Barak <mat...@mellanox.com> > --- > > Hi Doug, > This patch fixes a bug in the CM. In some flow, rb-tree could be > freed twice or used after it was freed. This bug was picked by > our regression tests and this fix was verified. > > Thanks, > Doron and Matan > > drivers/infiniband/core/cm.c | 10 +++++++++- > 1 file changed, 9 insertions(+), 1 deletion(-) > > diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c > index f5cf1c4..56ff0f3 100644 > --- a/drivers/infiniband/core/cm.c > +++ b/drivers/infiniband/core/cm.c > @@ -844,6 +844,11 @@ retest: > case IB_CM_SIDR_REQ_RCVD: > spin_unlock_irq(&cm_id_priv->lock); > cm_reject_sidr_req(cm_id_priv, IB_SIDR_REJECT); > + spin_lock_irq(&cm.lock); > + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) > + rb_erase(&cm_id_priv->sidr_id_node, > + &cm.remote_sidr_table); > + spin_unlock_irq(&cm.lock); We should be able to use a return value from cm_reject_sidr_req() -- passed through from ib_send_cm_sidr_rep() to determine if the id was removed from the tree. > break; > case IB_CM_REQ_SENT: > case IB_CM_MRA_REQ_RCVD: > @@ -3210,7 +3215,10 @@ int ib_send_cm_sidr_rep(struct ib_cm_id *cm_id, > spin_unlock_irqrestore(&cm_id_priv->lock, flags); > > spin_lock_irqsave(&cm.lock, flags); > - rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); > + if (!RB_EMPTY_NODE(&cm_id_priv->sidr_id_node)) { > + rb_erase(&cm_id_priv->sidr_id_node, &cm.remote_sidr_table); > + RB_CLEAR_NODE(&cm_id_priv->sidr_id_node); > + } > spin_unlock_irqrestore(&cm.lock, flags); Something is very wrong in this function if the id is not in the tree at this point. -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html