[openib-general] Re: [PATCH 3/3] iWARP CM
Sean Hefty
mshefty at ichips.intel.com
Wed Mar 15 16:34:20 PST 2006
Tom Tucker wrote:
> +static inline void iwcm_deref_id(struct iwcm_id_private *cm_id_priv)
> +{
> + if (atomic_dec_and_test(&cm_id_priv->refcount))
> + kfree(cm_id_priv);
> +}
I'm wary of code that does this. This can typically result in a race condition
where the user can receive a callback after destroy returns.
> +/* Clean up all resources associated with the connection. Set the
> + * cm_id state to DESTROYING so queued events will be ignored and
> + * subsequent events will not be queued.
> + */
The problem is that a callback could be just about to be invoked, when the user
calls destroy. Destroy executes and returns before the callback thread hits
their code. We need to block in destroy until all callbacks complete.
Otherwise, the user can never safely release any resources associated with this
cm_id.
> +void iw_destroy_cm_id(struct iw_cm_id *cm_id)
> +{
> + struct iwcm_id_private *iwcm_id_priv;
> + unsigned long flags;
> + struct ib_qp *qp;
> + int ret = 0;
> +
> + iwcm_id_priv = container_of(cm_id, struct iwcm_id_private, id);
> +
> + spin_lock_irqsave(&iwcm_id_priv->lock, flags);
> + switch (cm_id->state) {
> + case IW_CM_STATE_LISTEN:
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + ret = cm_id->device->iwcm->destroy_listen(cm_id);
> + break;
> + case IW_CM_STATE_CONN_RECV:
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + /* Need to call reject on behalf of client */
> + (void)iw_cm_reject(cm_id, NULL, 0);
> + break;
> + case IW_CM_STATE_CONN_SENT:
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + cm_id->qp = NULL;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + break;
> + case IW_CM_STATE_ESTABLISHED:
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + qp = cm_id->qp;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + ret = iwcm_modify_qp_err(qp);
> + break;
> + case IW_CM_STATE_IDLE:
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + break;
> + case IW_CM_STATE_CLOSING:
> + /* Lost race with cm_disconnect_handler. Need to
> + * release 'connect' reference, since setting state to
> + * DESTROYING will case CLOSE event to be ignored.
> + */
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + iwcm_deref_id(iwcm_id_priv);
> + break;
> + default:
> + /* Lost race with cm_close_handler. */
> + cm_id->state = IW_CM_STATE_DESTROYING;
> + spin_unlock_irqrestore(&iwcm_id_priv->lock, flags);
> + }
> + iwcm_deref_id(iwcm_id_priv);
> +}
> +EXPORT_SYMBOL(iw_destroy_cm_id);
- Sean
More information about the general
mailing list