diff options
Diffstat (limited to 'drivers/infiniband/core/cm.c')
-rw-r--r-- | drivers/infiniband/core/cm.c | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index dbddddd6fb5d..3a972ebf3c0d 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -169,6 +169,7 @@ struct cm_device { | |||
169 | struct ib_device *ib_device; | 169 | struct ib_device *ib_device; |
170 | struct device *device; | 170 | struct device *device; |
171 | u8 ack_delay; | 171 | u8 ack_delay; |
172 | int going_down; | ||
172 | struct cm_port *port[0]; | 173 | struct cm_port *port[0]; |
173 | }; | 174 | }; |
174 | 175 | ||
@@ -805,6 +806,11 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv) | |||
805 | { | 806 | { |
806 | int wait_time; | 807 | int wait_time; |
807 | unsigned long flags; | 808 | unsigned long flags; |
809 | struct cm_device *cm_dev; | ||
810 | |||
811 | cm_dev = ib_get_client_data(cm_id_priv->id.device, &cm_client); | ||
812 | if (!cm_dev) | ||
813 | return; | ||
808 | 814 | ||
809 | spin_lock_irqsave(&cm.lock, flags); | 815 | spin_lock_irqsave(&cm.lock, flags); |
810 | cm_cleanup_timewait(cm_id_priv->timewait_info); | 816 | cm_cleanup_timewait(cm_id_priv->timewait_info); |
@@ -818,8 +824,14 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv) | |||
818 | */ | 824 | */ |
819 | cm_id_priv->id.state = IB_CM_TIMEWAIT; | 825 | cm_id_priv->id.state = IB_CM_TIMEWAIT; |
820 | wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); | 826 | wait_time = cm_convert_to_ms(cm_id_priv->av.timeout); |
821 | queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, | 827 | |
822 | msecs_to_jiffies(wait_time)); | 828 | /* Check if the device started its remove_one */ |
829 | spin_lock_irq(&cm.lock); | ||
830 | if (!cm_dev->going_down) | ||
831 | queue_delayed_work(cm.wq, &cm_id_priv->timewait_info->work.work, | ||
832 | msecs_to_jiffies(wait_time)); | ||
833 | spin_unlock_irq(&cm.lock); | ||
834 | |||
823 | cm_id_priv->timewait_info = NULL; | 835 | cm_id_priv->timewait_info = NULL; |
824 | } | 836 | } |
825 | 837 | ||
@@ -3305,6 +3317,11 @@ static int cm_establish(struct ib_cm_id *cm_id) | |||
3305 | struct cm_work *work; | 3317 | struct cm_work *work; |
3306 | unsigned long flags; | 3318 | unsigned long flags; |
3307 | int ret = 0; | 3319 | int ret = 0; |
3320 | struct cm_device *cm_dev; | ||
3321 | |||
3322 | cm_dev = ib_get_client_data(cm_id->device, &cm_client); | ||
3323 | if (!cm_dev) | ||
3324 | return -ENODEV; | ||
3308 | 3325 | ||
3309 | work = kmalloc(sizeof *work, GFP_ATOMIC); | 3326 | work = kmalloc(sizeof *work, GFP_ATOMIC); |
3310 | if (!work) | 3327 | if (!work) |
@@ -3343,7 +3360,17 @@ static int cm_establish(struct ib_cm_id *cm_id) | |||
3343 | work->remote_id = cm_id->remote_id; | 3360 | work->remote_id = cm_id->remote_id; |
3344 | work->mad_recv_wc = NULL; | 3361 | work->mad_recv_wc = NULL; |
3345 | work->cm_event.event = IB_CM_USER_ESTABLISHED; | 3362 | work->cm_event.event = IB_CM_USER_ESTABLISHED; |
3346 | queue_delayed_work(cm.wq, &work->work, 0); | 3363 | |
3364 | /* Check if the device started its remove_one */ | ||
3365 | spin_lock_irq(&cm.lock); | ||
3366 | if (!cm_dev->going_down) { | ||
3367 | queue_delayed_work(cm.wq, &work->work, 0); | ||
3368 | } else { | ||
3369 | kfree(work); | ||
3370 | ret = -ENODEV; | ||
3371 | } | ||
3372 | spin_unlock_irq(&cm.lock); | ||
3373 | |||
3347 | out: | 3374 | out: |
3348 | return ret; | 3375 | return ret; |
3349 | } | 3376 | } |
@@ -3394,6 +3421,7 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, | |||
3394 | enum ib_cm_event_type event; | 3421 | enum ib_cm_event_type event; |
3395 | u16 attr_id; | 3422 | u16 attr_id; |
3396 | int paths = 0; | 3423 | int paths = 0; |
3424 | int going_down = 0; | ||
3397 | 3425 | ||
3398 | switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { | 3426 | switch (mad_recv_wc->recv_buf.mad->mad_hdr.attr_id) { |
3399 | case CM_REQ_ATTR_ID: | 3427 | case CM_REQ_ATTR_ID: |
@@ -3452,7 +3480,19 @@ static void cm_recv_handler(struct ib_mad_agent *mad_agent, | |||
3452 | work->cm_event.event = event; | 3480 | work->cm_event.event = event; |
3453 | work->mad_recv_wc = mad_recv_wc; | 3481 | work->mad_recv_wc = mad_recv_wc; |
3454 | work->port = port; | 3482 | work->port = port; |
3455 | queue_delayed_work(cm.wq, &work->work, 0); | 3483 | |
3484 | /* Check if the device started its remove_one */ | ||
3485 | spin_lock_irq(&cm.lock); | ||
3486 | if (!port->cm_dev->going_down) | ||
3487 | queue_delayed_work(cm.wq, &work->work, 0); | ||
3488 | else | ||
3489 | going_down = 1; | ||
3490 | spin_unlock_irq(&cm.lock); | ||
3491 | |||
3492 | if (going_down) { | ||
3493 | kfree(work); | ||
3494 | ib_free_recv_mad(mad_recv_wc); | ||
3495 | } | ||
3456 | } | 3496 | } |
3457 | 3497 | ||
3458 | static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, | 3498 | static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, |
@@ -3771,7 +3811,7 @@ static void cm_add_one(struct ib_device *ib_device) | |||
3771 | 3811 | ||
3772 | cm_dev->ib_device = ib_device; | 3812 | cm_dev->ib_device = ib_device; |
3773 | cm_get_ack_delay(cm_dev); | 3813 | cm_get_ack_delay(cm_dev); |
3774 | 3814 | cm_dev->going_down = 0; | |
3775 | cm_dev->device = device_create(&cm_class, &ib_device->dev, | 3815 | cm_dev->device = device_create(&cm_class, &ib_device->dev, |
3776 | MKDEV(0, 0), NULL, | 3816 | MKDEV(0, 0), NULL, |
3777 | "%s", ib_device->name); | 3817 | "%s", ib_device->name); |
@@ -3864,14 +3904,23 @@ static void cm_remove_one(struct ib_device *ib_device) | |||
3864 | list_del(&cm_dev->list); | 3904 | list_del(&cm_dev->list); |
3865 | write_unlock_irqrestore(&cm.device_lock, flags); | 3905 | write_unlock_irqrestore(&cm.device_lock, flags); |
3866 | 3906 | ||
3907 | spin_lock_irq(&cm.lock); | ||
3908 | cm_dev->going_down = 1; | ||
3909 | spin_unlock_irq(&cm.lock); | ||
3910 | |||
3867 | for (i = 1; i <= ib_device->phys_port_cnt; i++) { | 3911 | for (i = 1; i <= ib_device->phys_port_cnt; i++) { |
3868 | if (!rdma_cap_ib_cm(ib_device, i)) | 3912 | if (!rdma_cap_ib_cm(ib_device, i)) |
3869 | continue; | 3913 | continue; |
3870 | 3914 | ||
3871 | port = cm_dev->port[i-1]; | 3915 | port = cm_dev->port[i-1]; |
3872 | ib_modify_port(ib_device, port->port_num, 0, &port_modify); | 3916 | ib_modify_port(ib_device, port->port_num, 0, &port_modify); |
3873 | ib_unregister_mad_agent(port->mad_agent); | 3917 | /* |
3918 | * We flush the queue here after the going_down set, this | ||
3919 | * verify that no new works will be queued in the recv handler, | ||
3920 | * after that we can call the unregister_mad_agent | ||
3921 | */ | ||
3874 | flush_workqueue(cm.wq); | 3922 | flush_workqueue(cm.wq); |
3923 | ib_unregister_mad_agent(port->mad_agent); | ||
3875 | cm_remove_port_fs(port); | 3924 | cm_remove_port_fs(port); |
3876 | } | 3925 | } |
3877 | device_unregister(cm_dev->device); | 3926 | device_unregister(cm_dev->device); |