aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/infiniband
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/infiniband')
-rw-r--r--drivers/infiniband/core/cm.c54
1 files changed, 36 insertions, 18 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c
index f35fcc4c0638..470c482f2887 100644
--- a/drivers/infiniband/core/cm.c
+++ b/drivers/infiniband/core/cm.c
@@ -75,6 +75,7 @@ static struct ib_cm {
75 struct rb_root remote_sidr_table; 75 struct rb_root remote_sidr_table;
76 struct idr local_id_table; 76 struct idr local_id_table;
77 __be32 random_id_operand; 77 __be32 random_id_operand;
78 struct list_head timewait_list;
78 struct workqueue_struct *wq; 79 struct workqueue_struct *wq;
79} cm; 80} cm;
80 81
@@ -112,6 +113,7 @@ struct cm_work {
112 113
113struct cm_timewait_info { 114struct cm_timewait_info {
114 struct cm_work work; /* Must be first. */ 115 struct cm_work work; /* Must be first. */
116 struct list_head list;
115 struct rb_node remote_qp_node; 117 struct rb_node remote_qp_node;
116 struct rb_node remote_id_node; 118 struct rb_node remote_id_node;
117 __be64 remote_ca_guid; 119 __be64 remote_ca_guid;
@@ -647,13 +649,6 @@ static inline int cm_convert_to_ms(int iba_time)
647 649
648static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info) 650static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
649{ 651{
650 unsigned long flags;
651
652 if (!timewait_info->inserted_remote_id &&
653 !timewait_info->inserted_remote_qp)
654 return;
655
656 spin_lock_irqsave(&cm.lock, flags);
657 if (timewait_info->inserted_remote_id) { 652 if (timewait_info->inserted_remote_id) {
658 rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table); 653 rb_erase(&timewait_info->remote_id_node, &cm.remote_id_table);
659 timewait_info->inserted_remote_id = 0; 654 timewait_info->inserted_remote_id = 0;
@@ -663,7 +658,6 @@ static void cm_cleanup_timewait(struct cm_timewait_info *timewait_info)
663 rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table); 658 rb_erase(&timewait_info->remote_qp_node, &cm.remote_qp_table);
664 timewait_info->inserted_remote_qp = 0; 659 timewait_info->inserted_remote_qp = 0;
665 } 660 }
666 spin_unlock_irqrestore(&cm.lock, flags);
667} 661}
668 662
669static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id) 663static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
@@ -684,8 +678,12 @@ static struct cm_timewait_info * cm_create_timewait_info(__be32 local_id)
684static void cm_enter_timewait(struct cm_id_private *cm_id_priv) 678static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
685{ 679{
686 int wait_time; 680 int wait_time;
681 unsigned long flags;
687 682
683 spin_lock_irqsave(&cm.lock, flags);
688 cm_cleanup_timewait(cm_id_priv->timewait_info); 684 cm_cleanup_timewait(cm_id_priv->timewait_info);
685 list_add_tail(&cm_id_priv->timewait_info->list, &cm.timewait_list);
686 spin_unlock_irqrestore(&cm.lock, flags);
689 687
690 /* 688 /*
691 * The cm_id could be destroyed by the user before we exit timewait. 689 * The cm_id could be destroyed by the user before we exit timewait.
@@ -701,9 +699,13 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv)
701 699
702static void cm_reset_to_idle(struct cm_id_private *cm_id_priv) 700static void cm_reset_to_idle(struct cm_id_private *cm_id_priv)
703{ 701{
702 unsigned long flags;
703
704 cm_id_priv->id.state = IB_CM_IDLE; 704 cm_id_priv->id.state = IB_CM_IDLE;
705 if (cm_id_priv->timewait_info) { 705 if (cm_id_priv->timewait_info) {
706 spin_lock_irqsave(&cm.lock, flags);
706 cm_cleanup_timewait(cm_id_priv->timewait_info); 707 cm_cleanup_timewait(cm_id_priv->timewait_info);
708 spin_unlock_irqrestore(&cm.lock, flags);
707 kfree(cm_id_priv->timewait_info); 709 kfree(cm_id_priv->timewait_info);
708 cm_id_priv->timewait_info = NULL; 710 cm_id_priv->timewait_info = NULL;
709 } 711 }
@@ -1307,6 +1309,7 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1307 if (timewait_info) { 1309 if (timewait_info) {
1308 cur_cm_id_priv = cm_get_id(timewait_info->work.local_id, 1310 cur_cm_id_priv = cm_get_id(timewait_info->work.local_id,
1309 timewait_info->work.remote_id); 1311 timewait_info->work.remote_id);
1312 cm_cleanup_timewait(cm_id_priv->timewait_info);
1310 spin_unlock_irqrestore(&cm.lock, flags); 1313 spin_unlock_irqrestore(&cm.lock, flags);
1311 if (cur_cm_id_priv) { 1314 if (cur_cm_id_priv) {
1312 cm_dup_req_handler(work, cur_cm_id_priv); 1315 cm_dup_req_handler(work, cur_cm_id_priv);
@@ -1315,7 +1318,8 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1315 cm_issue_rej(work->port, work->mad_recv_wc, 1318 cm_issue_rej(work->port, work->mad_recv_wc,
1316 IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ, 1319 IB_CM_REJ_STALE_CONN, CM_MSG_RESPONSE_REQ,
1317 NULL, 0); 1320 NULL, 0);
1318 goto error; 1321 listen_cm_id_priv = NULL;
1322 goto out;
1319 } 1323 }
1320 1324
1321 /* Find matching listen request. */ 1325 /* Find matching listen request. */
@@ -1323,21 +1327,20 @@ static struct cm_id_private * cm_match_req(struct cm_work *work,
1323 req_msg->service_id, 1327 req_msg->service_id,
1324 req_msg->private_data); 1328 req_msg->private_data);
1325 if (!listen_cm_id_priv) { 1329 if (!listen_cm_id_priv) {
1330 cm_cleanup_timewait(cm_id_priv->timewait_info);
1326 spin_unlock_irqrestore(&cm.lock, flags); 1331 spin_unlock_irqrestore(&cm.lock, flags);
1327 cm_issue_rej(work->port, work->mad_recv_wc, 1332 cm_issue_rej(work->port, work->mad_recv_wc,
1328 IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ, 1333 IB_CM_REJ_INVALID_SERVICE_ID, CM_MSG_RESPONSE_REQ,
1329 NULL, 0); 1334 NULL, 0);
1330 goto error; 1335 goto out;
1331 } 1336 }
1332 atomic_inc(&listen_cm_id_priv->refcount); 1337 atomic_inc(&listen_cm_id_priv->refcount);
1333 atomic_inc(&cm_id_priv->refcount); 1338 atomic_inc(&cm_id_priv->refcount);
1334 cm_id_priv->id.state = IB_CM_REQ_RCVD; 1339 cm_id_priv->id.state = IB_CM_REQ_RCVD;
1335 atomic_inc(&cm_id_priv->work_count); 1340 atomic_inc(&cm_id_priv->work_count);
1336 spin_unlock_irqrestore(&cm.lock, flags); 1341 spin_unlock_irqrestore(&cm.lock, flags);
1342out:
1337 return listen_cm_id_priv; 1343 return listen_cm_id_priv;
1338
1339error: cm_cleanup_timewait(cm_id_priv->timewait_info);
1340 return NULL;
1341} 1344}
1342 1345
1343static int cm_req_handler(struct cm_work *work) 1346static int cm_req_handler(struct cm_work *work)
@@ -2601,28 +2604,29 @@ static int cm_timewait_handler(struct cm_work *work)
2601{ 2604{
2602 struct cm_timewait_info *timewait_info; 2605 struct cm_timewait_info *timewait_info;
2603 struct cm_id_private *cm_id_priv; 2606 struct cm_id_private *cm_id_priv;
2604 unsigned long flags;
2605 int ret; 2607 int ret;
2606 2608
2607 timewait_info = (struct cm_timewait_info *)work; 2609 timewait_info = (struct cm_timewait_info *)work;
2608 cm_cleanup_timewait(timewait_info); 2610 spin_lock_irq(&cm.lock);
2611 list_del(&timewait_info->list);
2612 spin_unlock_irq(&cm.lock);
2609 2613
2610 cm_id_priv = cm_acquire_id(timewait_info->work.local_id, 2614 cm_id_priv = cm_acquire_id(timewait_info->work.local_id,
2611 timewait_info->work.remote_id); 2615 timewait_info->work.remote_id);
2612 if (!cm_id_priv) 2616 if (!cm_id_priv)
2613 return -EINVAL; 2617 return -EINVAL;
2614 2618
2615 spin_lock_irqsave(&cm_id_priv->lock, flags); 2619 spin_lock_irq(&cm_id_priv->lock);
2616 if (cm_id_priv->id.state != IB_CM_TIMEWAIT || 2620 if (cm_id_priv->id.state != IB_CM_TIMEWAIT ||
2617 cm_id_priv->remote_qpn != timewait_info->remote_qpn) { 2621 cm_id_priv->remote_qpn != timewait_info->remote_qpn) {
2618 spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2622 spin_unlock_irq(&cm_id_priv->lock);
2619 goto out; 2623 goto out;
2620 } 2624 }
2621 cm_id_priv->id.state = IB_CM_IDLE; 2625 cm_id_priv->id.state = IB_CM_IDLE;
2622 ret = atomic_inc_and_test(&cm_id_priv->work_count); 2626 ret = atomic_inc_and_test(&cm_id_priv->work_count);
2623 if (!ret) 2627 if (!ret)
2624 list_add_tail(&work->list, &cm_id_priv->work_list); 2628 list_add_tail(&work->list, &cm_id_priv->work_list);
2625 spin_unlock_irqrestore(&cm_id_priv->lock, flags); 2629 spin_unlock_irq(&cm_id_priv->lock);
2626 2630
2627 if (ret) 2631 if (ret)
2628 cm_process_work(cm_id_priv, work); 2632 cm_process_work(cm_id_priv, work);
@@ -3374,6 +3378,7 @@ static int __init ib_cm_init(void)
3374 idr_init(&cm.local_id_table); 3378 idr_init(&cm.local_id_table);
3375 get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); 3379 get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand);
3376 idr_pre_get(&cm.local_id_table, GFP_KERNEL); 3380 idr_pre_get(&cm.local_id_table, GFP_KERNEL);
3381 INIT_LIST_HEAD(&cm.timewait_list);
3377 3382
3378 cm.wq = create_workqueue("ib_cm"); 3383 cm.wq = create_workqueue("ib_cm");
3379 if (!cm.wq) 3384 if (!cm.wq)
@@ -3391,7 +3396,20 @@ error:
3391 3396
3392static void __exit ib_cm_cleanup(void) 3397static void __exit ib_cm_cleanup(void)
3393{ 3398{
3399 struct cm_timewait_info *timewait_info, *tmp;
3400
3401 spin_lock_irq(&cm.lock);
3402 list_for_each_entry(timewait_info, &cm.timewait_list, list)
3403 cancel_delayed_work(&timewait_info->work.work);
3404 spin_unlock_irq(&cm.lock);
3405
3394 destroy_workqueue(cm.wq); 3406 destroy_workqueue(cm.wq);
3407
3408 list_for_each_entry_safe(timewait_info, tmp, &cm.timewait_list, list) {
3409 list_del(&timewait_info->list);
3410 kfree(timewait_info);
3411 }
3412
3395 ib_unregister_client(&cm_client); 3413 ib_unregister_client(&cm_client);
3396 idr_destroy(&cm.local_id_table); 3414 idr_destroy(&cm.local_id_table);
3397} 3415}