rdma_join_multicast() allocates struct cma_multicast and then proceeds to join to a multicast address. However, the join operation completes in another context and the allocated struct could be released if the user destroys either the rdma_id object or decides to leave the multicast group while the join operation is in progress. This patch uses a kref object to maintain reference counting to avoid such situation.
Signed-off-by: Eli Cohen <[email protected]> --- Changes from previous version: I removed the protection of mc list manipulation using spinlocks becuase - a. In order to break into different patches b. I have doubts as for the necessity of this protection. drivers/infiniband/core/cma.c | 20 ++++++++++++++++---- 1 files changed, 16 insertions(+), 4 deletions(-) diff --git a/drivers/infiniband/core/cma.c b/drivers/infiniband/core/cma.c index 851de83..aa62101 100644 --- a/drivers/infiniband/core/cma.c +++ b/drivers/infiniband/core/cma.c @@ -157,6 +157,7 @@ struct cma_multicast { struct list_head list; void *context; struct sockaddr_storage addr; + struct kref mcref; }; struct cma_work { @@ -290,6 +291,13 @@ static inline void cma_deref_dev(struct cma_device *cma_dev) complete(&cma_dev->comp); } +void release_mc(struct kref *kref) +{ + struct cma_multicast *mc = container_of(kref, struct cma_multicast, mcref); + + kfree(mc); +} + static void cma_detach_from_dev(struct rdma_id_private *id_priv) { list_del(&id_priv->list); @@ -827,7 +835,7 @@ static void cma_leave_mc_groups(struct rdma_id_private *id_priv) struct cma_multicast, list); list_del(&mc->list); ib_sa_free_multicast(mc->multicast.ib); - kfree(mc); + kref_put(&mc->mcref, release_mc); } } @@ -2643,7 +2651,7 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) id_priv = mc->id_priv; if (cma_disable_callback(id_priv, CMA_ADDR_BOUND) && cma_disable_callback(id_priv, CMA_ADDR_RESOLVED)) - return 0; + goto out; mutex_lock(&id_priv->qp_mutex); if (!status && id_priv->id.qp) @@ -2669,10 +2677,12 @@ static int cma_ib_mc_handler(int status, struct ib_sa_multicast *multicast) cma_exch(id_priv, CMA_DESTROYING); mutex_unlock(&id_priv->handler_mutex); rdma_destroy_id(&id_priv->id); - return 0; + goto out; } mutex_unlock(&id_priv->handler_mutex); +out: + kref_put(&mc->mcref, release_mc); return 0; } @@ -2759,11 +2769,13 @@ int rdma_join_multicast(struct rdma_cm_id *id, struct sockaddr *addr, memcpy(&mc->addr, addr, ip_addr_size(addr)); mc->context = context; mc->id_priv = id_priv; + kref_init(&mc->mcref); spin_lock(&id_priv->lock); list_add(&mc->list, &id_priv->mc_list); spin_unlock(&id_priv->lock); + kref_get(&mc->mcref); switch (rdma_node_get_transport(id->device->node_type)) { case RDMA_TRANSPORT_IB: ret = cma_join_ib_multicast(id_priv, mc); @@ -2800,7 +2812,7 @@ void rdma_leave_multicast(struct rdma_cm_id *id, struct sockaddr *addr) &mc->multicast.ib->rec.mgid, mc->multicast.ib->rec.mlid); ib_sa_free_multicast(mc->multicast.ib); - kfree(mc); + kref_put(&mc->mcref, release_mc); return; } } -- 1.6.3.3 _______________________________________________ general mailing list [email protected] http://lists.openfabrics.org/cgi-bin/mailman/listinfo/general To unsubscribe, please visit http://openib.org/mailman/listinfo/openib-general
