diff options
Diffstat (limited to 'drivers/infiniband/core/cm.c')
-rw-r--r-- | drivers/infiniband/core/cm.c | 66 |
1 files changed, 45 insertions, 21 deletions
diff --git a/drivers/infiniband/core/cm.c b/drivers/infiniband/core/cm.c index 0de335b7bfc..f35fcc4c063 100644 --- a/drivers/infiniband/core/cm.c +++ b/drivers/infiniband/core/cm.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. | 2 | * Copyright (c) 2004-2006 Intel Corporation. All rights reserved. |
3 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. | 3 | * Copyright (c) 2004 Topspin Corporation. All rights reserved. |
4 | * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. | 4 | * Copyright (c) 2004, 2005 Voltaire Corporation. All rights reserved. |
5 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. | 5 | * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. |
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/idr.h> | 41 | #include <linux/idr.h> |
42 | #include <linux/interrupt.h> | 42 | #include <linux/interrupt.h> |
43 | #include <linux/pci.h> | 43 | #include <linux/pci.h> |
44 | #include <linux/random.h> | ||
44 | #include <linux/rbtree.h> | 45 | #include <linux/rbtree.h> |
45 | #include <linux/spinlock.h> | 46 | #include <linux/spinlock.h> |
46 | #include <linux/workqueue.h> | 47 | #include <linux/workqueue.h> |
@@ -73,6 +74,7 @@ static struct ib_cm { | |||
73 | struct rb_root remote_id_table; | 74 | struct rb_root remote_id_table; |
74 | struct rb_root remote_sidr_table; | 75 | struct rb_root remote_sidr_table; |
75 | struct idr local_id_table; | 76 | struct idr local_id_table; |
77 | __be32 random_id_operand; | ||
76 | struct workqueue_struct *wq; | 78 | struct workqueue_struct *wq; |
77 | } cm; | 79 | } cm; |
78 | 80 | ||
@@ -177,7 +179,7 @@ static int cm_alloc_msg(struct cm_id_private *cm_id_priv, | |||
177 | if (IS_ERR(ah)) | 179 | if (IS_ERR(ah)) |
178 | return PTR_ERR(ah); | 180 | return PTR_ERR(ah); |
179 | 181 | ||
180 | m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, | 182 | m = ib_create_send_mad(mad_agent, cm_id_priv->id.remote_cm_qpn, |
181 | cm_id_priv->av.pkey_index, | 183 | cm_id_priv->av.pkey_index, |
182 | 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, | 184 | 0, IB_MGMT_MAD_HDR, IB_MGMT_MAD_DATA, |
183 | GFP_ATOMIC); | 185 | GFP_ATOMIC); |
@@ -299,15 +301,17 @@ static int cm_init_av_by_path(struct ib_sa_path_rec *path, struct cm_av *av) | |||
299 | static int cm_alloc_id(struct cm_id_private *cm_id_priv) | 301 | static int cm_alloc_id(struct cm_id_private *cm_id_priv) |
300 | { | 302 | { |
301 | unsigned long flags; | 303 | unsigned long flags; |
302 | int ret; | 304 | int ret, id; |
303 | static int next_id; | 305 | static int next_id; |
304 | 306 | ||
305 | do { | 307 | do { |
306 | spin_lock_irqsave(&cm.lock, flags); | 308 | spin_lock_irqsave(&cm.lock, flags); |
307 | ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, next_id++, | 309 | ret = idr_get_new_above(&cm.local_id_table, cm_id_priv, |
308 | (__force int *) &cm_id_priv->id.local_id); | 310 | next_id++, &id); |
309 | spin_unlock_irqrestore(&cm.lock, flags); | 311 | spin_unlock_irqrestore(&cm.lock, flags); |
310 | } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); | 312 | } while( (ret == -EAGAIN) && idr_pre_get(&cm.local_id_table, GFP_KERNEL) ); |
313 | |||
314 | cm_id_priv->id.local_id = (__force __be32) (id ^ cm.random_id_operand); | ||
311 | return ret; | 315 | return ret; |
312 | } | 316 | } |
313 | 317 | ||
@@ -316,7 +320,8 @@ static void cm_free_id(__be32 local_id) | |||
316 | unsigned long flags; | 320 | unsigned long flags; |
317 | 321 | ||
318 | spin_lock_irqsave(&cm.lock, flags); | 322 | spin_lock_irqsave(&cm.lock, flags); |
319 | idr_remove(&cm.local_id_table, (__force int) local_id); | 323 | idr_remove(&cm.local_id_table, |
324 | (__force int) (local_id ^ cm.random_id_operand)); | ||
320 | spin_unlock_irqrestore(&cm.lock, flags); | 325 | spin_unlock_irqrestore(&cm.lock, flags); |
321 | } | 326 | } |
322 | 327 | ||
@@ -324,7 +329,8 @@ static struct cm_id_private * cm_get_id(__be32 local_id, __be32 remote_id) | |||
324 | { | 329 | { |
325 | struct cm_id_private *cm_id_priv; | 330 | struct cm_id_private *cm_id_priv; |
326 | 331 | ||
327 | cm_id_priv = idr_find(&cm.local_id_table, (__force int) local_id); | 332 | cm_id_priv = idr_find(&cm.local_id_table, |
333 | (__force int) (local_id ^ cm.random_id_operand)); | ||
328 | if (cm_id_priv) { | 334 | if (cm_id_priv) { |
329 | if (cm_id_priv->id.remote_id == remote_id) | 335 | if (cm_id_priv->id.remote_id == remote_id) |
330 | atomic_inc(&cm_id_priv->refcount); | 336 | atomic_inc(&cm_id_priv->refcount); |
@@ -679,6 +685,8 @@ static void cm_enter_timewait(struct cm_id_private *cm_id_priv) | |||
679 | { | 685 | { |
680 | int wait_time; | 686 | int wait_time; |
681 | 687 | ||
688 | cm_cleanup_timewait(cm_id_priv->timewait_info); | ||
689 | |||
682 | /* | 690 | /* |
683 | * The cm_id could be destroyed by the user before we exit timewait. | 691 | * The cm_id could be destroyed by the user before we exit timewait. |
684 | * To protect against this, we search for the cm_id after exiting | 692 | * To protect against this, we search for the cm_id after exiting |
@@ -1354,7 +1362,7 @@ static int cm_req_handler(struct cm_work *work) | |||
1354 | id.local_id); | 1362 | id.local_id); |
1355 | if (IS_ERR(cm_id_priv->timewait_info)) { | 1363 | if (IS_ERR(cm_id_priv->timewait_info)) { |
1356 | ret = PTR_ERR(cm_id_priv->timewait_info); | 1364 | ret = PTR_ERR(cm_id_priv->timewait_info); |
1357 | goto error1; | 1365 | goto destroy; |
1358 | } | 1366 | } |
1359 | cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id; | 1367 | cm_id_priv->timewait_info->work.remote_id = req_msg->local_comm_id; |
1360 | cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid; | 1368 | cm_id_priv->timewait_info->remote_ca_guid = req_msg->local_ca_guid; |
@@ -1363,7 +1371,8 @@ static int cm_req_handler(struct cm_work *work) | |||
1363 | listen_cm_id_priv = cm_match_req(work, cm_id_priv); | 1371 | listen_cm_id_priv = cm_match_req(work, cm_id_priv); |
1364 | if (!listen_cm_id_priv) { | 1372 | if (!listen_cm_id_priv) { |
1365 | ret = -EINVAL; | 1373 | ret = -EINVAL; |
1366 | goto error2; | 1374 | kfree(cm_id_priv->timewait_info); |
1375 | goto destroy; | ||
1367 | } | 1376 | } |
1368 | 1377 | ||
1369 | cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; | 1378 | cm_id_priv->id.cm_handler = listen_cm_id_priv->id.cm_handler; |
@@ -1373,12 +1382,22 @@ static int cm_req_handler(struct cm_work *work) | |||
1373 | 1382 | ||
1374 | cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]); | 1383 | cm_format_paths_from_req(req_msg, &work->path[0], &work->path[1]); |
1375 | ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av); | 1384 | ret = cm_init_av_by_path(&work->path[0], &cm_id_priv->av); |
1376 | if (ret) | 1385 | if (ret) { |
1377 | goto error3; | 1386 | ib_get_cached_gid(work->port->cm_dev->device, |
1387 | work->port->port_num, 0, &work->path[0].sgid); | ||
1388 | ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_GID, | ||
1389 | &work->path[0].sgid, sizeof work->path[0].sgid, | ||
1390 | NULL, 0); | ||
1391 | goto rejected; | ||
1392 | } | ||
1378 | if (req_msg->alt_local_lid) { | 1393 | if (req_msg->alt_local_lid) { |
1379 | ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av); | 1394 | ret = cm_init_av_by_path(&work->path[1], &cm_id_priv->alt_av); |
1380 | if (ret) | 1395 | if (ret) { |
1381 | goto error3; | 1396 | ib_send_cm_rej(cm_id, IB_CM_REJ_INVALID_ALT_GID, |
1397 | &work->path[0].sgid, | ||
1398 | sizeof work->path[0].sgid, NULL, 0); | ||
1399 | goto rejected; | ||
1400 | } | ||
1382 | } | 1401 | } |
1383 | cm_id_priv->tid = req_msg->hdr.tid; | 1402 | cm_id_priv->tid = req_msg->hdr.tid; |
1384 | cm_id_priv->timeout_ms = cm_convert_to_ms( | 1403 | cm_id_priv->timeout_ms = cm_convert_to_ms( |
@@ -1400,12 +1419,11 @@ static int cm_req_handler(struct cm_work *work) | |||
1400 | cm_deref_id(listen_cm_id_priv); | 1419 | cm_deref_id(listen_cm_id_priv); |
1401 | return 0; | 1420 | return 0; |
1402 | 1421 | ||
1403 | error3: atomic_dec(&cm_id_priv->refcount); | 1422 | rejected: |
1423 | atomic_dec(&cm_id_priv->refcount); | ||
1404 | cm_deref_id(listen_cm_id_priv); | 1424 | cm_deref_id(listen_cm_id_priv); |
1405 | cm_cleanup_timewait(cm_id_priv->timewait_info); | 1425 | destroy: |
1406 | error2: kfree(cm_id_priv->timewait_info); | 1426 | ib_destroy_cm_id(cm_id); |
1407 | cm_id_priv->timewait_info = NULL; | ||
1408 | error1: ib_destroy_cm_id(&cm_id_priv->id); | ||
1409 | return ret; | 1427 | return ret; |
1410 | } | 1428 | } |
1411 | 1429 | ||
@@ -2072,8 +2090,9 @@ static struct cm_id_private * cm_acquire_rejected_id(struct cm_rej_msg *rej_msg) | |||
2072 | spin_unlock_irqrestore(&cm.lock, flags); | 2090 | spin_unlock_irqrestore(&cm.lock, flags); |
2073 | return NULL; | 2091 | return NULL; |
2074 | } | 2092 | } |
2075 | cm_id_priv = idr_find(&cm.local_id_table, | 2093 | cm_id_priv = idr_find(&cm.local_id_table, (__force int) |
2076 | (__force int) timewait_info->work.local_id); | 2094 | (timewait_info->work.local_id ^ |
2095 | cm.random_id_operand)); | ||
2077 | if (cm_id_priv) { | 2096 | if (cm_id_priv) { |
2078 | if (cm_id_priv->id.remote_id == remote_id) | 2097 | if (cm_id_priv->id.remote_id == remote_id) |
2079 | atomic_inc(&cm_id_priv->refcount); | 2098 | atomic_inc(&cm_id_priv->refcount); |
@@ -3125,7 +3144,8 @@ static int cm_init_qp_init_attr(struct cm_id_private *cm_id_priv, | |||
3125 | qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | | 3144 | qp_attr->qp_access_flags = IB_ACCESS_LOCAL_WRITE | |
3126 | IB_ACCESS_REMOTE_WRITE; | 3145 | IB_ACCESS_REMOTE_WRITE; |
3127 | if (cm_id_priv->responder_resources) | 3146 | if (cm_id_priv->responder_resources) |
3128 | qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ; | 3147 | qp_attr->qp_access_flags |= IB_ACCESS_REMOTE_READ | |
3148 | IB_ACCESS_REMOTE_ATOMIC; | ||
3129 | qp_attr->pkey_index = cm_id_priv->av.pkey_index; | 3149 | qp_attr->pkey_index = cm_id_priv->av.pkey_index; |
3130 | qp_attr->port_num = cm_id_priv->av.port->port_num; | 3150 | qp_attr->port_num = cm_id_priv->av.port->port_num; |
3131 | ret = 0; | 3151 | ret = 0; |
@@ -3262,6 +3282,9 @@ static void cm_add_one(struct ib_device *device) | |||
3262 | int ret; | 3282 | int ret; |
3263 | u8 i; | 3283 | u8 i; |
3264 | 3284 | ||
3285 | if (rdma_node_get_transport(device->node_type) != RDMA_TRANSPORT_IB) | ||
3286 | return; | ||
3287 | |||
3265 | cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) * | 3288 | cm_dev = kmalloc(sizeof(*cm_dev) + sizeof(*port) * |
3266 | device->phys_port_cnt, GFP_KERNEL); | 3289 | device->phys_port_cnt, GFP_KERNEL); |
3267 | if (!cm_dev) | 3290 | if (!cm_dev) |
@@ -3349,6 +3372,7 @@ static int __init ib_cm_init(void) | |||
3349 | cm.remote_qp_table = RB_ROOT; | 3372 | cm.remote_qp_table = RB_ROOT; |
3350 | cm.remote_sidr_table = RB_ROOT; | 3373 | cm.remote_sidr_table = RB_ROOT; |
3351 | idr_init(&cm.local_id_table); | 3374 | idr_init(&cm.local_id_table); |
3375 | get_random_bytes(&cm.random_id_operand, sizeof cm.random_id_operand); | ||
3352 | idr_pre_get(&cm.local_id_table, GFP_KERNEL); | 3376 | idr_pre_get(&cm.local_id_table, GFP_KERNEL); |
3353 | 3377 | ||
3354 | cm.wq = create_workqueue("ib_cm"); | 3378 | cm.wq = create_workqueue("ib_cm"); |