Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.9-rc1 1397 lines 33 kB view raw
1/* 2 * Copyright (c) 2005-2006 Intel Corporation. All rights reserved. 3 * 4 * This software is available to you under a choice of one of two 5 * licenses. You may choose to be licensed under the terms of the GNU 6 * General Public License (GPL) Version 2, available from the file 7 * COPYING in the main directory of this source tree, or the 8 * OpenIB.org BSD license below: 9 * 10 * Redistribution and use in source and binary forms, with or 11 * without modification, are permitted provided that the following 12 * conditions are met: 13 * 14 * - Redistributions of source code must retain the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer. 17 * 18 * - Redistributions in binary form must reproduce the above 19 * copyright notice, this list of conditions and the following 20 * disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 30 * SOFTWARE. 31 */ 32 33#include <linux/completion.h> 34#include <linux/file.h> 35#include <linux/mutex.h> 36#include <linux/poll.h> 37#include <linux/sched.h> 38#include <linux/idr.h> 39#include <linux/in.h> 40#include <linux/in6.h> 41#include <linux/miscdevice.h> 42#include <linux/slab.h> 43#include <linux/sysctl.h> 44#include <linux/module.h> 45 46#include <rdma/rdma_user_cm.h> 47#include <rdma/ib_marshall.h> 48#include <rdma/rdma_cm.h> 49#include <rdma/rdma_cm_ib.h> 50 51MODULE_AUTHOR("Sean Hefty"); 52MODULE_DESCRIPTION("RDMA Userspace Connection Manager Access"); 53MODULE_LICENSE("Dual BSD/GPL"); 54 55static unsigned int max_backlog = 1024; 56 57static struct ctl_table_header *ucma_ctl_table_hdr; 58static ctl_table ucma_ctl_table[] = { 59 { 60 .procname = "max_backlog", 61 .data = &max_backlog, 62 .maxlen = sizeof max_backlog, 63 .mode = 0644, 64 .proc_handler = proc_dointvec, 65 }, 66 { } 67}; 68 69struct ucma_file { 70 struct mutex mut; 71 struct file *filp; 72 struct list_head ctx_list; 73 struct list_head event_list; 74 wait_queue_head_t poll_wait; 75}; 76 77struct ucma_context { 78 int id; 79 struct completion comp; 80 atomic_t ref; 81 int events_reported; 82 int backlog; 83 84 struct ucma_file *file; 85 struct rdma_cm_id *cm_id; 86 u64 uid; 87 88 struct list_head list; 89 struct list_head mc_list; 90}; 91 92struct ucma_multicast { 93 struct ucma_context *ctx; 94 int id; 95 int events_reported; 96 97 u64 uid; 98 struct list_head list; 99 struct sockaddr_storage addr; 100}; 101 102struct ucma_event { 103 struct ucma_context *ctx; 104 struct ucma_multicast *mc; 105 struct list_head list; 106 struct rdma_cm_id *cm_id; 107 struct rdma_ucm_event_resp resp; 108}; 109 110static DEFINE_MUTEX(mut); 111static DEFINE_IDR(ctx_idr); 112static DEFINE_IDR(multicast_idr); 113 114static inline struct ucma_context *_ucma_find_context(int id, 115 struct ucma_file *file) 116{ 117 struct ucma_context *ctx; 118 119 ctx = idr_find(&ctx_idr, id); 120 if (!ctx) 121 ctx = ERR_PTR(-ENOENT); 122 else if (ctx->file != file) 123 ctx = ERR_PTR(-EINVAL); 124 return ctx; 125} 126 127static struct ucma_context *ucma_get_ctx(struct ucma_file *file, int id) 128{ 129 struct ucma_context *ctx; 130 131 mutex_lock(&mut); 132 ctx = _ucma_find_context(id, file); 133 if (!IS_ERR(ctx)) 134 atomic_inc(&ctx->ref); 135 mutex_unlock(&mut); 136 return ctx; 137} 138 139static void ucma_put_ctx(struct ucma_context *ctx) 140{ 141 if (atomic_dec_and_test(&ctx->ref)) 142 complete(&ctx->comp); 143} 144 145static struct ucma_context *ucma_alloc_ctx(struct ucma_file *file) 146{ 147 struct ucma_context *ctx; 148 149 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); 150 if (!ctx) 151 return NULL; 152 153 atomic_set(&ctx->ref, 1); 154 init_completion(&ctx->comp); 155 INIT_LIST_HEAD(&ctx->mc_list); 156 ctx->file = file; 157 158 mutex_lock(&mut); 159 ctx->id = idr_alloc(&ctx_idr, ctx, 0, 0, GFP_KERNEL); 160 mutex_unlock(&mut); 161 if (ctx->id < 0) 162 goto error; 163 164 list_add_tail(&ctx->list, &file->ctx_list); 165 return ctx; 166 167error: 168 kfree(ctx); 169 return NULL; 170} 171 172static struct ucma_multicast* ucma_alloc_multicast(struct ucma_context *ctx) 173{ 174 struct ucma_multicast *mc; 175 176 mc = kzalloc(sizeof(*mc), GFP_KERNEL); 177 if (!mc) 178 return NULL; 179 180 mutex_lock(&mut); 181 mc->id = idr_alloc(&multicast_idr, mc, 0, 0, GFP_KERNEL); 182 mutex_unlock(&mut); 183 if (mc->id < 0) 184 goto error; 185 186 mc->ctx = ctx; 187 list_add_tail(&mc->list, &ctx->mc_list); 188 return mc; 189 190error: 191 kfree(mc); 192 return NULL; 193} 194 195static void ucma_copy_conn_event(struct rdma_ucm_conn_param *dst, 196 struct rdma_conn_param *src) 197{ 198 if (src->private_data_len) 199 memcpy(dst->private_data, src->private_data, 200 src->private_data_len); 201 dst->private_data_len = src->private_data_len; 202 dst->responder_resources =src->responder_resources; 203 dst->initiator_depth = src->initiator_depth; 204 dst->flow_control = src->flow_control; 205 dst->retry_count = src->retry_count; 206 dst->rnr_retry_count = src->rnr_retry_count; 207 dst->srq = src->srq; 208 dst->qp_num = src->qp_num; 209} 210 211static void ucma_copy_ud_event(struct rdma_ucm_ud_param *dst, 212 struct rdma_ud_param *src) 213{ 214 if (src->private_data_len) 215 memcpy(dst->private_data, src->private_data, 216 src->private_data_len); 217 dst->private_data_len = src->private_data_len; 218 ib_copy_ah_attr_to_user(&dst->ah_attr, &src->ah_attr); 219 dst->qp_num = src->qp_num; 220 dst->qkey = src->qkey; 221} 222 223static void ucma_set_event_context(struct ucma_context *ctx, 224 struct rdma_cm_event *event, 225 struct ucma_event *uevent) 226{ 227 uevent->ctx = ctx; 228 switch (event->event) { 229 case RDMA_CM_EVENT_MULTICAST_JOIN: 230 case RDMA_CM_EVENT_MULTICAST_ERROR: 231 uevent->mc = (struct ucma_multicast *) 232 event->param.ud.private_data; 233 uevent->resp.uid = uevent->mc->uid; 234 uevent->resp.id = uevent->mc->id; 235 break; 236 default: 237 uevent->resp.uid = ctx->uid; 238 uevent->resp.id = ctx->id; 239 break; 240 } 241} 242 243static int ucma_event_handler(struct rdma_cm_id *cm_id, 244 struct rdma_cm_event *event) 245{ 246 struct ucma_event *uevent; 247 struct ucma_context *ctx = cm_id->context; 248 int ret = 0; 249 250 uevent = kzalloc(sizeof(*uevent), GFP_KERNEL); 251 if (!uevent) 252 return event->event == RDMA_CM_EVENT_CONNECT_REQUEST; 253 254 mutex_lock(&ctx->file->mut); 255 uevent->cm_id = cm_id; 256 ucma_set_event_context(ctx, event, uevent); 257 uevent->resp.event = event->event; 258 uevent->resp.status = event->status; 259 if (cm_id->qp_type == IB_QPT_UD) 260 ucma_copy_ud_event(&uevent->resp.param.ud, &event->param.ud); 261 else 262 ucma_copy_conn_event(&uevent->resp.param.conn, 263 &event->param.conn); 264 265 if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST) { 266 if (!ctx->backlog) { 267 ret = -ENOMEM; 268 kfree(uevent); 269 goto out; 270 } 271 ctx->backlog--; 272 } else if (!ctx->uid) { 273 /* 274 * We ignore events for new connections until userspace has set 275 * their context. This can only happen if an error occurs on a 276 * new connection before the user accepts it. This is okay, 277 * since the accept will just fail later. 278 */ 279 kfree(uevent); 280 goto out; 281 } 282 283 list_add_tail(&uevent->list, &ctx->file->event_list); 284 wake_up_interruptible(&ctx->file->poll_wait); 285out: 286 mutex_unlock(&ctx->file->mut); 287 return ret; 288} 289 290static ssize_t ucma_get_event(struct ucma_file *file, const char __user *inbuf, 291 int in_len, int out_len) 292{ 293 struct ucma_context *ctx; 294 struct rdma_ucm_get_event cmd; 295 struct ucma_event *uevent; 296 int ret = 0; 297 298 if (out_len < sizeof uevent->resp) 299 return -ENOSPC; 300 301 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 302 return -EFAULT; 303 304 mutex_lock(&file->mut); 305 while (list_empty(&file->event_list)) { 306 mutex_unlock(&file->mut); 307 308 if (file->filp->f_flags & O_NONBLOCK) 309 return -EAGAIN; 310 311 if (wait_event_interruptible(file->poll_wait, 312 !list_empty(&file->event_list))) 313 return -ERESTARTSYS; 314 315 mutex_lock(&file->mut); 316 } 317 318 uevent = list_entry(file->event_list.next, struct ucma_event, list); 319 320 if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) { 321 ctx = ucma_alloc_ctx(file); 322 if (!ctx) { 323 ret = -ENOMEM; 324 goto done; 325 } 326 uevent->ctx->backlog++; 327 ctx->cm_id = uevent->cm_id; 328 ctx->cm_id->context = ctx; 329 uevent->resp.id = ctx->id; 330 } 331 332 if (copy_to_user((void __user *)(unsigned long)cmd.response, 333 &uevent->resp, sizeof uevent->resp)) { 334 ret = -EFAULT; 335 goto done; 336 } 337 338 list_del(&uevent->list); 339 uevent->ctx->events_reported++; 340 if (uevent->mc) 341 uevent->mc->events_reported++; 342 kfree(uevent); 343done: 344 mutex_unlock(&file->mut); 345 return ret; 346} 347 348static int ucma_get_qp_type(struct rdma_ucm_create_id *cmd, enum ib_qp_type *qp_type) 349{ 350 switch (cmd->ps) { 351 case RDMA_PS_TCP: 352 *qp_type = IB_QPT_RC; 353 return 0; 354 case RDMA_PS_UDP: 355 case RDMA_PS_IPOIB: 356 *qp_type = IB_QPT_UD; 357 return 0; 358 case RDMA_PS_IB: 359 *qp_type = cmd->qp_type; 360 return 0; 361 default: 362 return -EINVAL; 363 } 364} 365 366static ssize_t ucma_create_id(struct ucma_file *file, const char __user *inbuf, 367 int in_len, int out_len) 368{ 369 struct rdma_ucm_create_id cmd; 370 struct rdma_ucm_create_id_resp resp; 371 struct ucma_context *ctx; 372 enum ib_qp_type qp_type; 373 int ret; 374 375 if (out_len < sizeof(resp)) 376 return -ENOSPC; 377 378 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 379 return -EFAULT; 380 381 ret = ucma_get_qp_type(&cmd, &qp_type); 382 if (ret) 383 return ret; 384 385 mutex_lock(&file->mut); 386 ctx = ucma_alloc_ctx(file); 387 mutex_unlock(&file->mut); 388 if (!ctx) 389 return -ENOMEM; 390 391 ctx->uid = cmd.uid; 392 ctx->cm_id = rdma_create_id(ucma_event_handler, ctx, cmd.ps, qp_type); 393 if (IS_ERR(ctx->cm_id)) { 394 ret = PTR_ERR(ctx->cm_id); 395 goto err1; 396 } 397 398 resp.id = ctx->id; 399 if (copy_to_user((void __user *)(unsigned long)cmd.response, 400 &resp, sizeof(resp))) { 401 ret = -EFAULT; 402 goto err2; 403 } 404 return 0; 405 406err2: 407 rdma_destroy_id(ctx->cm_id); 408err1: 409 mutex_lock(&mut); 410 idr_remove(&ctx_idr, ctx->id); 411 mutex_unlock(&mut); 412 kfree(ctx); 413 return ret; 414} 415 416static void ucma_cleanup_multicast(struct ucma_context *ctx) 417{ 418 struct ucma_multicast *mc, *tmp; 419 420 mutex_lock(&mut); 421 list_for_each_entry_safe(mc, tmp, &ctx->mc_list, list) { 422 list_del(&mc->list); 423 idr_remove(&multicast_idr, mc->id); 424 kfree(mc); 425 } 426 mutex_unlock(&mut); 427} 428 429static void ucma_cleanup_mc_events(struct ucma_multicast *mc) 430{ 431 struct ucma_event *uevent, *tmp; 432 433 list_for_each_entry_safe(uevent, tmp, &mc->ctx->file->event_list, list) { 434 if (uevent->mc != mc) 435 continue; 436 437 list_del(&uevent->list); 438 kfree(uevent); 439 } 440} 441 442/* 443 * We cannot hold file->mut when calling rdma_destroy_id() or we can 444 * deadlock. We also acquire file->mut in ucma_event_handler(), and 445 * rdma_destroy_id() will wait until all callbacks have completed. 446 */ 447static int ucma_free_ctx(struct ucma_context *ctx) 448{ 449 int events_reported; 450 struct ucma_event *uevent, *tmp; 451 LIST_HEAD(list); 452 453 /* No new events will be generated after destroying the id. */ 454 rdma_destroy_id(ctx->cm_id); 455 456 ucma_cleanup_multicast(ctx); 457 458 /* Cleanup events not yet reported to the user. */ 459 mutex_lock(&ctx->file->mut); 460 list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) { 461 if (uevent->ctx == ctx) 462 list_move_tail(&uevent->list, &list); 463 } 464 list_del(&ctx->list); 465 mutex_unlock(&ctx->file->mut); 466 467 list_for_each_entry_safe(uevent, tmp, &list, list) { 468 list_del(&uevent->list); 469 if (uevent->resp.event == RDMA_CM_EVENT_CONNECT_REQUEST) 470 rdma_destroy_id(uevent->cm_id); 471 kfree(uevent); 472 } 473 474 events_reported = ctx->events_reported; 475 kfree(ctx); 476 return events_reported; 477} 478 479static ssize_t ucma_destroy_id(struct ucma_file *file, const char __user *inbuf, 480 int in_len, int out_len) 481{ 482 struct rdma_ucm_destroy_id cmd; 483 struct rdma_ucm_destroy_id_resp resp; 484 struct ucma_context *ctx; 485 int ret = 0; 486 487 if (out_len < sizeof(resp)) 488 return -ENOSPC; 489 490 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 491 return -EFAULT; 492 493 mutex_lock(&mut); 494 ctx = _ucma_find_context(cmd.id, file); 495 if (!IS_ERR(ctx)) 496 idr_remove(&ctx_idr, ctx->id); 497 mutex_unlock(&mut); 498 499 if (IS_ERR(ctx)) 500 return PTR_ERR(ctx); 501 502 ucma_put_ctx(ctx); 503 wait_for_completion(&ctx->comp); 504 resp.events_reported = ucma_free_ctx(ctx); 505 506 if (copy_to_user((void __user *)(unsigned long)cmd.response, 507 &resp, sizeof(resp))) 508 ret = -EFAULT; 509 510 return ret; 511} 512 513static ssize_t ucma_bind_addr(struct ucma_file *file, const char __user *inbuf, 514 int in_len, int out_len) 515{ 516 struct rdma_ucm_bind_addr cmd; 517 struct ucma_context *ctx; 518 int ret; 519 520 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 521 return -EFAULT; 522 523 ctx = ucma_get_ctx(file, cmd.id); 524 if (IS_ERR(ctx)) 525 return PTR_ERR(ctx); 526 527 ret = rdma_bind_addr(ctx->cm_id, (struct sockaddr *) &cmd.addr); 528 ucma_put_ctx(ctx); 529 return ret; 530} 531 532static ssize_t ucma_resolve_addr(struct ucma_file *file, 533 const char __user *inbuf, 534 int in_len, int out_len) 535{ 536 struct rdma_ucm_resolve_addr cmd; 537 struct ucma_context *ctx; 538 int ret; 539 540 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 541 return -EFAULT; 542 543 ctx = ucma_get_ctx(file, cmd.id); 544 if (IS_ERR(ctx)) 545 return PTR_ERR(ctx); 546 547 ret = rdma_resolve_addr(ctx->cm_id, (struct sockaddr *) &cmd.src_addr, 548 (struct sockaddr *) &cmd.dst_addr, 549 cmd.timeout_ms); 550 ucma_put_ctx(ctx); 551 return ret; 552} 553 554static ssize_t ucma_resolve_route(struct ucma_file *file, 555 const char __user *inbuf, 556 int in_len, int out_len) 557{ 558 struct rdma_ucm_resolve_route cmd; 559 struct ucma_context *ctx; 560 int ret; 561 562 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 563 return -EFAULT; 564 565 ctx = ucma_get_ctx(file, cmd.id); 566 if (IS_ERR(ctx)) 567 return PTR_ERR(ctx); 568 569 ret = rdma_resolve_route(ctx->cm_id, cmd.timeout_ms); 570 ucma_put_ctx(ctx); 571 return ret; 572} 573 574static void ucma_copy_ib_route(struct rdma_ucm_query_route_resp *resp, 575 struct rdma_route *route) 576{ 577 struct rdma_dev_addr *dev_addr; 578 579 resp->num_paths = route->num_paths; 580 switch (route->num_paths) { 581 case 0: 582 dev_addr = &route->addr.dev_addr; 583 rdma_addr_get_dgid(dev_addr, 584 (union ib_gid *) &resp->ib_route[0].dgid); 585 rdma_addr_get_sgid(dev_addr, 586 (union ib_gid *) &resp->ib_route[0].sgid); 587 resp->ib_route[0].pkey = cpu_to_be16(ib_addr_get_pkey(dev_addr)); 588 break; 589 case 2: 590 ib_copy_path_rec_to_user(&resp->ib_route[1], 591 &route->path_rec[1]); 592 /* fall through */ 593 case 1: 594 ib_copy_path_rec_to_user(&resp->ib_route[0], 595 &route->path_rec[0]); 596 break; 597 default: 598 break; 599 } 600} 601 602static void ucma_copy_iboe_route(struct rdma_ucm_query_route_resp *resp, 603 struct rdma_route *route) 604{ 605 struct rdma_dev_addr *dev_addr; 606 struct net_device *dev; 607 u16 vid = 0; 608 609 resp->num_paths = route->num_paths; 610 switch (route->num_paths) { 611 case 0: 612 dev_addr = &route->addr.dev_addr; 613 dev = dev_get_by_index(&init_net, dev_addr->bound_dev_if); 614 if (dev) { 615 vid = rdma_vlan_dev_vlan_id(dev); 616 dev_put(dev); 617 } 618 619 iboe_mac_vlan_to_ll((union ib_gid *) &resp->ib_route[0].dgid, 620 dev_addr->dst_dev_addr, vid); 621 iboe_addr_get_sgid(dev_addr, 622 (union ib_gid *) &resp->ib_route[0].sgid); 623 resp->ib_route[0].pkey = cpu_to_be16(0xffff); 624 break; 625 case 2: 626 ib_copy_path_rec_to_user(&resp->ib_route[1], 627 &route->path_rec[1]); 628 /* fall through */ 629 case 1: 630 ib_copy_path_rec_to_user(&resp->ib_route[0], 631 &route->path_rec[0]); 632 break; 633 default: 634 break; 635 } 636} 637 638static void ucma_copy_iw_route(struct rdma_ucm_query_route_resp *resp, 639 struct rdma_route *route) 640{ 641 struct rdma_dev_addr *dev_addr; 642 643 dev_addr = &route->addr.dev_addr; 644 rdma_addr_get_dgid(dev_addr, (union ib_gid *) &resp->ib_route[0].dgid); 645 rdma_addr_get_sgid(dev_addr, (union ib_gid *) &resp->ib_route[0].sgid); 646} 647 648static ssize_t ucma_query_route(struct ucma_file *file, 649 const char __user *inbuf, 650 int in_len, int out_len) 651{ 652 struct rdma_ucm_query_route cmd; 653 struct rdma_ucm_query_route_resp resp; 654 struct ucma_context *ctx; 655 struct sockaddr *addr; 656 int ret = 0; 657 658 if (out_len < sizeof(resp)) 659 return -ENOSPC; 660 661 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 662 return -EFAULT; 663 664 ctx = ucma_get_ctx(file, cmd.id); 665 if (IS_ERR(ctx)) 666 return PTR_ERR(ctx); 667 668 memset(&resp, 0, sizeof resp); 669 addr = (struct sockaddr *) &ctx->cm_id->route.addr.src_addr; 670 memcpy(&resp.src_addr, addr, addr->sa_family == AF_INET ? 671 sizeof(struct sockaddr_in) : 672 sizeof(struct sockaddr_in6)); 673 addr = (struct sockaddr *) &ctx->cm_id->route.addr.dst_addr; 674 memcpy(&resp.dst_addr, addr, addr->sa_family == AF_INET ? 675 sizeof(struct sockaddr_in) : 676 sizeof(struct sockaddr_in6)); 677 if (!ctx->cm_id->device) 678 goto out; 679 680 resp.node_guid = (__force __u64) ctx->cm_id->device->node_guid; 681 resp.port_num = ctx->cm_id->port_num; 682 switch (rdma_node_get_transport(ctx->cm_id->device->node_type)) { 683 case RDMA_TRANSPORT_IB: 684 switch (rdma_port_get_link_layer(ctx->cm_id->device, 685 ctx->cm_id->port_num)) { 686 case IB_LINK_LAYER_INFINIBAND: 687 ucma_copy_ib_route(&resp, &ctx->cm_id->route); 688 break; 689 case IB_LINK_LAYER_ETHERNET: 690 ucma_copy_iboe_route(&resp, &ctx->cm_id->route); 691 break; 692 default: 693 break; 694 } 695 break; 696 case RDMA_TRANSPORT_IWARP: 697 ucma_copy_iw_route(&resp, &ctx->cm_id->route); 698 break; 699 default: 700 break; 701 } 702 703out: 704 if (copy_to_user((void __user *)(unsigned long)cmd.response, 705 &resp, sizeof(resp))) 706 ret = -EFAULT; 707 708 ucma_put_ctx(ctx); 709 return ret; 710} 711 712static void ucma_copy_conn_param(struct rdma_conn_param *dst, 713 struct rdma_ucm_conn_param *src) 714{ 715 dst->private_data = src->private_data; 716 dst->private_data_len = src->private_data_len; 717 dst->responder_resources =src->responder_resources; 718 dst->initiator_depth = src->initiator_depth; 719 dst->flow_control = src->flow_control; 720 dst->retry_count = src->retry_count; 721 dst->rnr_retry_count = src->rnr_retry_count; 722 dst->srq = src->srq; 723 dst->qp_num = src->qp_num; 724} 725 726static ssize_t ucma_connect(struct ucma_file *file, const char __user *inbuf, 727 int in_len, int out_len) 728{ 729 struct rdma_ucm_connect cmd; 730 struct rdma_conn_param conn_param; 731 struct ucma_context *ctx; 732 int ret; 733 734 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 735 return -EFAULT; 736 737 if (!cmd.conn_param.valid) 738 return -EINVAL; 739 740 ctx = ucma_get_ctx(file, cmd.id); 741 if (IS_ERR(ctx)) 742 return PTR_ERR(ctx); 743 744 ucma_copy_conn_param(&conn_param, &cmd.conn_param); 745 ret = rdma_connect(ctx->cm_id, &conn_param); 746 ucma_put_ctx(ctx); 747 return ret; 748} 749 750static ssize_t ucma_listen(struct ucma_file *file, const char __user *inbuf, 751 int in_len, int out_len) 752{ 753 struct rdma_ucm_listen cmd; 754 struct ucma_context *ctx; 755 int ret; 756 757 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 758 return -EFAULT; 759 760 ctx = ucma_get_ctx(file, cmd.id); 761 if (IS_ERR(ctx)) 762 return PTR_ERR(ctx); 763 764 ctx->backlog = cmd.backlog > 0 && cmd.backlog < max_backlog ? 765 cmd.backlog : max_backlog; 766 ret = rdma_listen(ctx->cm_id, ctx->backlog); 767 ucma_put_ctx(ctx); 768 return ret; 769} 770 771static ssize_t ucma_accept(struct ucma_file *file, const char __user *inbuf, 772 int in_len, int out_len) 773{ 774 struct rdma_ucm_accept cmd; 775 struct rdma_conn_param conn_param; 776 struct ucma_context *ctx; 777 int ret; 778 779 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 780 return -EFAULT; 781 782 ctx = ucma_get_ctx(file, cmd.id); 783 if (IS_ERR(ctx)) 784 return PTR_ERR(ctx); 785 786 if (cmd.conn_param.valid) { 787 ucma_copy_conn_param(&conn_param, &cmd.conn_param); 788 mutex_lock(&file->mut); 789 ret = rdma_accept(ctx->cm_id, &conn_param); 790 if (!ret) 791 ctx->uid = cmd.uid; 792 mutex_unlock(&file->mut); 793 } else 794 ret = rdma_accept(ctx->cm_id, NULL); 795 796 ucma_put_ctx(ctx); 797 return ret; 798} 799 800static ssize_t ucma_reject(struct ucma_file *file, const char __user *inbuf, 801 int in_len, int out_len) 802{ 803 struct rdma_ucm_reject cmd; 804 struct ucma_context *ctx; 805 int ret; 806 807 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 808 return -EFAULT; 809 810 ctx = ucma_get_ctx(file, cmd.id); 811 if (IS_ERR(ctx)) 812 return PTR_ERR(ctx); 813 814 ret = rdma_reject(ctx->cm_id, cmd.private_data, cmd.private_data_len); 815 ucma_put_ctx(ctx); 816 return ret; 817} 818 819static ssize_t ucma_disconnect(struct ucma_file *file, const char __user *inbuf, 820 int in_len, int out_len) 821{ 822 struct rdma_ucm_disconnect cmd; 823 struct ucma_context *ctx; 824 int ret; 825 826 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 827 return -EFAULT; 828 829 ctx = ucma_get_ctx(file, cmd.id); 830 if (IS_ERR(ctx)) 831 return PTR_ERR(ctx); 832 833 ret = rdma_disconnect(ctx->cm_id); 834 ucma_put_ctx(ctx); 835 return ret; 836} 837 838static ssize_t ucma_init_qp_attr(struct ucma_file *file, 839 const char __user *inbuf, 840 int in_len, int out_len) 841{ 842 struct rdma_ucm_init_qp_attr cmd; 843 struct ib_uverbs_qp_attr resp; 844 struct ucma_context *ctx; 845 struct ib_qp_attr qp_attr; 846 int ret; 847 848 if (out_len < sizeof(resp)) 849 return -ENOSPC; 850 851 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 852 return -EFAULT; 853 854 ctx = ucma_get_ctx(file, cmd.id); 855 if (IS_ERR(ctx)) 856 return PTR_ERR(ctx); 857 858 resp.qp_attr_mask = 0; 859 memset(&qp_attr, 0, sizeof qp_attr); 860 qp_attr.qp_state = cmd.qp_state; 861 ret = rdma_init_qp_attr(ctx->cm_id, &qp_attr, &resp.qp_attr_mask); 862 if (ret) 863 goto out; 864 865 ib_copy_qp_attr_to_user(&resp, &qp_attr); 866 if (copy_to_user((void __user *)(unsigned long)cmd.response, 867 &resp, sizeof(resp))) 868 ret = -EFAULT; 869 870out: 871 ucma_put_ctx(ctx); 872 return ret; 873} 874 875static int ucma_set_option_id(struct ucma_context *ctx, int optname, 876 void *optval, size_t optlen) 877{ 878 int ret = 0; 879 880 switch (optname) { 881 case RDMA_OPTION_ID_TOS: 882 if (optlen != sizeof(u8)) { 883 ret = -EINVAL; 884 break; 885 } 886 rdma_set_service_type(ctx->cm_id, *((u8 *) optval)); 887 break; 888 case RDMA_OPTION_ID_REUSEADDR: 889 if (optlen != sizeof(int)) { 890 ret = -EINVAL; 891 break; 892 } 893 ret = rdma_set_reuseaddr(ctx->cm_id, *((int *) optval) ? 1 : 0); 894 break; 895 case RDMA_OPTION_ID_AFONLY: 896 if (optlen != sizeof(int)) { 897 ret = -EINVAL; 898 break; 899 } 900 ret = rdma_set_afonly(ctx->cm_id, *((int *) optval) ? 1 : 0); 901 break; 902 default: 903 ret = -ENOSYS; 904 } 905 906 return ret; 907} 908 909static int ucma_set_ib_path(struct ucma_context *ctx, 910 struct ib_path_rec_data *path_data, size_t optlen) 911{ 912 struct ib_sa_path_rec sa_path; 913 struct rdma_cm_event event; 914 int ret; 915 916 if (optlen % sizeof(*path_data)) 917 return -EINVAL; 918 919 for (; optlen; optlen -= sizeof(*path_data), path_data++) { 920 if (path_data->flags == (IB_PATH_GMP | IB_PATH_PRIMARY | 921 IB_PATH_BIDIRECTIONAL)) 922 break; 923 } 924 925 if (!optlen) 926 return -EINVAL; 927 928 ib_sa_unpack_path(path_data->path_rec, &sa_path); 929 ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1); 930 if (ret) 931 return ret; 932 933 memset(&event, 0, sizeof event); 934 event.event = RDMA_CM_EVENT_ROUTE_RESOLVED; 935 return ucma_event_handler(ctx->cm_id, &event); 936} 937 938static int ucma_set_option_ib(struct ucma_context *ctx, int optname, 939 void *optval, size_t optlen) 940{ 941 int ret; 942 943 switch (optname) { 944 case RDMA_OPTION_IB_PATH: 945 ret = ucma_set_ib_path(ctx, optval, optlen); 946 break; 947 default: 948 ret = -ENOSYS; 949 } 950 951 return ret; 952} 953 954static int ucma_set_option_level(struct ucma_context *ctx, int level, 955 int optname, void *optval, size_t optlen) 956{ 957 int ret; 958 959 switch (level) { 960 case RDMA_OPTION_ID: 961 ret = ucma_set_option_id(ctx, optname, optval, optlen); 962 break; 963 case RDMA_OPTION_IB: 964 ret = ucma_set_option_ib(ctx, optname, optval, optlen); 965 break; 966 default: 967 ret = -ENOSYS; 968 } 969 970 return ret; 971} 972 973static ssize_t ucma_set_option(struct ucma_file *file, const char __user *inbuf, 974 int in_len, int out_len) 975{ 976 struct rdma_ucm_set_option cmd; 977 struct ucma_context *ctx; 978 void *optval; 979 int ret; 980 981 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 982 return -EFAULT; 983 984 ctx = ucma_get_ctx(file, cmd.id); 985 if (IS_ERR(ctx)) 986 return PTR_ERR(ctx); 987 988 optval = memdup_user((void __user *) (unsigned long) cmd.optval, 989 cmd.optlen); 990 if (IS_ERR(optval)) { 991 ret = PTR_ERR(optval); 992 goto out; 993 } 994 995 ret = ucma_set_option_level(ctx, cmd.level, cmd.optname, optval, 996 cmd.optlen); 997 kfree(optval); 998 999out: 1000 ucma_put_ctx(ctx); 1001 return ret; 1002} 1003 1004static ssize_t ucma_notify(struct ucma_file *file, const char __user *inbuf, 1005 int in_len, int out_len) 1006{ 1007 struct rdma_ucm_notify cmd; 1008 struct ucma_context *ctx; 1009 int ret; 1010 1011 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 1012 return -EFAULT; 1013 1014 ctx = ucma_get_ctx(file, cmd.id); 1015 if (IS_ERR(ctx)) 1016 return PTR_ERR(ctx); 1017 1018 ret = rdma_notify(ctx->cm_id, (enum ib_event_type) cmd.event); 1019 ucma_put_ctx(ctx); 1020 return ret; 1021} 1022 1023static ssize_t ucma_join_multicast(struct ucma_file *file, 1024 const char __user *inbuf, 1025 int in_len, int out_len) 1026{ 1027 struct rdma_ucm_join_mcast cmd; 1028 struct rdma_ucm_create_id_resp resp; 1029 struct ucma_context *ctx; 1030 struct ucma_multicast *mc; 1031 int ret; 1032 1033 if (out_len < sizeof(resp)) 1034 return -ENOSPC; 1035 1036 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 1037 return -EFAULT; 1038 1039 ctx = ucma_get_ctx(file, cmd.id); 1040 if (IS_ERR(ctx)) 1041 return PTR_ERR(ctx); 1042 1043 mutex_lock(&file->mut); 1044 mc = ucma_alloc_multicast(ctx); 1045 if (!mc) { 1046 ret = -ENOMEM; 1047 goto err1; 1048 } 1049 1050 mc->uid = cmd.uid; 1051 memcpy(&mc->addr, &cmd.addr, sizeof cmd.addr); 1052 ret = rdma_join_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr, mc); 1053 if (ret) 1054 goto err2; 1055 1056 resp.id = mc->id; 1057 if (copy_to_user((void __user *)(unsigned long)cmd.response, 1058 &resp, sizeof(resp))) { 1059 ret = -EFAULT; 1060 goto err3; 1061 } 1062 1063 mutex_unlock(&file->mut); 1064 ucma_put_ctx(ctx); 1065 return 0; 1066 1067err3: 1068 rdma_leave_multicast(ctx->cm_id, (struct sockaddr *) &mc->addr); 1069 ucma_cleanup_mc_events(mc); 1070err2: 1071 mutex_lock(&mut); 1072 idr_remove(&multicast_idr, mc->id); 1073 mutex_unlock(&mut); 1074 list_del(&mc->list); 1075 kfree(mc); 1076err1: 1077 mutex_unlock(&file->mut); 1078 ucma_put_ctx(ctx); 1079 return ret; 1080} 1081 1082static ssize_t ucma_leave_multicast(struct ucma_file *file, 1083 const char __user *inbuf, 1084 int in_len, int out_len) 1085{ 1086 struct rdma_ucm_destroy_id cmd; 1087 struct rdma_ucm_destroy_id_resp resp; 1088 struct ucma_multicast *mc; 1089 int ret = 0; 1090 1091 if (out_len < sizeof(resp)) 1092 return -ENOSPC; 1093 1094 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 1095 return -EFAULT; 1096 1097 mutex_lock(&mut); 1098 mc = idr_find(&multicast_idr, cmd.id); 1099 if (!mc) 1100 mc = ERR_PTR(-ENOENT); 1101 else if (mc->ctx->file != file) 1102 mc = ERR_PTR(-EINVAL); 1103 else { 1104 idr_remove(&multicast_idr, mc->id); 1105 atomic_inc(&mc->ctx->ref); 1106 } 1107 mutex_unlock(&mut); 1108 1109 if (IS_ERR(mc)) { 1110 ret = PTR_ERR(mc); 1111 goto out; 1112 } 1113 1114 rdma_leave_multicast(mc->ctx->cm_id, (struct sockaddr *) &mc->addr); 1115 mutex_lock(&mc->ctx->file->mut); 1116 ucma_cleanup_mc_events(mc); 1117 list_del(&mc->list); 1118 mutex_unlock(&mc->ctx->file->mut); 1119 1120 ucma_put_ctx(mc->ctx); 1121 resp.events_reported = mc->events_reported; 1122 kfree(mc); 1123 1124 if (copy_to_user((void __user *)(unsigned long)cmd.response, 1125 &resp, sizeof(resp))) 1126 ret = -EFAULT; 1127out: 1128 return ret; 1129} 1130 1131static void ucma_lock_files(struct ucma_file *file1, struct ucma_file *file2) 1132{ 1133 /* Acquire mutex's based on pointer comparison to prevent deadlock. */ 1134 if (file1 < file2) { 1135 mutex_lock(&file1->mut); 1136 mutex_lock(&file2->mut); 1137 } else { 1138 mutex_lock(&file2->mut); 1139 mutex_lock(&file1->mut); 1140 } 1141} 1142 1143static void ucma_unlock_files(struct ucma_file *file1, struct ucma_file *file2) 1144{ 1145 if (file1 < file2) { 1146 mutex_unlock(&file2->mut); 1147 mutex_unlock(&file1->mut); 1148 } else { 1149 mutex_unlock(&file1->mut); 1150 mutex_unlock(&file2->mut); 1151 } 1152} 1153 1154static void ucma_move_events(struct ucma_context *ctx, struct ucma_file *file) 1155{ 1156 struct ucma_event *uevent, *tmp; 1157 1158 list_for_each_entry_safe(uevent, tmp, &ctx->file->event_list, list) 1159 if (uevent->ctx == ctx) 1160 list_move_tail(&uevent->list, &file->event_list); 1161} 1162 1163static ssize_t ucma_migrate_id(struct ucma_file *new_file, 1164 const char __user *inbuf, 1165 int in_len, int out_len) 1166{ 1167 struct rdma_ucm_migrate_id cmd; 1168 struct rdma_ucm_migrate_resp resp; 1169 struct ucma_context *ctx; 1170 struct fd f; 1171 struct ucma_file *cur_file; 1172 int ret = 0; 1173 1174 if (copy_from_user(&cmd, inbuf, sizeof(cmd))) 1175 return -EFAULT; 1176 1177 /* Get current fd to protect against it being closed */ 1178 f = fdget(cmd.fd); 1179 if (!f.file) 1180 return -ENOENT; 1181 1182 /* Validate current fd and prevent destruction of id. */ 1183 ctx = ucma_get_ctx(f.file->private_data, cmd.id); 1184 if (IS_ERR(ctx)) { 1185 ret = PTR_ERR(ctx); 1186 goto file_put; 1187 } 1188 1189 cur_file = ctx->file; 1190 if (cur_file == new_file) { 1191 resp.events_reported = ctx->events_reported; 1192 goto response; 1193 } 1194 1195 /* 1196 * Migrate events between fd's, maintaining order, and avoiding new 1197 * events being added before existing events. 1198 */ 1199 ucma_lock_files(cur_file, new_file); 1200 mutex_lock(&mut); 1201 1202 list_move_tail(&ctx->list, &new_file->ctx_list); 1203 ucma_move_events(ctx, new_file); 1204 ctx->file = new_file; 1205 resp.events_reported = ctx->events_reported; 1206 1207 mutex_unlock(&mut); 1208 ucma_unlock_files(cur_file, new_file); 1209 1210response: 1211 if (copy_to_user((void __user *)(unsigned long)cmd.response, 1212 &resp, sizeof(resp))) 1213 ret = -EFAULT; 1214 1215 ucma_put_ctx(ctx); 1216file_put: 1217 fdput(f); 1218 return ret; 1219} 1220 1221static ssize_t (*ucma_cmd_table[])(struct ucma_file *file, 1222 const char __user *inbuf, 1223 int in_len, int out_len) = { 1224 [RDMA_USER_CM_CMD_CREATE_ID] = ucma_create_id, 1225 [RDMA_USER_CM_CMD_DESTROY_ID] = ucma_destroy_id, 1226 [RDMA_USER_CM_CMD_BIND_ADDR] = ucma_bind_addr, 1227 [RDMA_USER_CM_CMD_RESOLVE_ADDR] = ucma_resolve_addr, 1228 [RDMA_USER_CM_CMD_RESOLVE_ROUTE]= ucma_resolve_route, 1229 [RDMA_USER_CM_CMD_QUERY_ROUTE] = ucma_query_route, 1230 [RDMA_USER_CM_CMD_CONNECT] = ucma_connect, 1231 [RDMA_USER_CM_CMD_LISTEN] = ucma_listen, 1232 [RDMA_USER_CM_CMD_ACCEPT] = ucma_accept, 1233 [RDMA_USER_CM_CMD_REJECT] = ucma_reject, 1234 [RDMA_USER_CM_CMD_DISCONNECT] = ucma_disconnect, 1235 [RDMA_USER_CM_CMD_INIT_QP_ATTR] = ucma_init_qp_attr, 1236 [RDMA_USER_CM_CMD_GET_EVENT] = ucma_get_event, 1237 [RDMA_USER_CM_CMD_GET_OPTION] = NULL, 1238 [RDMA_USER_CM_CMD_SET_OPTION] = ucma_set_option, 1239 [RDMA_USER_CM_CMD_NOTIFY] = ucma_notify, 1240 [RDMA_USER_CM_CMD_JOIN_MCAST] = ucma_join_multicast, 1241 [RDMA_USER_CM_CMD_LEAVE_MCAST] = ucma_leave_multicast, 1242 [RDMA_USER_CM_CMD_MIGRATE_ID] = ucma_migrate_id 1243}; 1244 1245static ssize_t ucma_write(struct file *filp, const char __user *buf, 1246 size_t len, loff_t *pos) 1247{ 1248 struct ucma_file *file = filp->private_data; 1249 struct rdma_ucm_cmd_hdr hdr; 1250 ssize_t ret; 1251 1252 if (len < sizeof(hdr)) 1253 return -EINVAL; 1254 1255 if (copy_from_user(&hdr, buf, sizeof(hdr))) 1256 return -EFAULT; 1257 1258 if (hdr.cmd >= ARRAY_SIZE(ucma_cmd_table)) 1259 return -EINVAL; 1260 1261 if (hdr.in + sizeof(hdr) > len) 1262 return -EINVAL; 1263 1264 if (!ucma_cmd_table[hdr.cmd]) 1265 return -ENOSYS; 1266 1267 ret = ucma_cmd_table[hdr.cmd](file, buf + sizeof(hdr), hdr.in, hdr.out); 1268 if (!ret) 1269 ret = len; 1270 1271 return ret; 1272} 1273 1274static unsigned int ucma_poll(struct file *filp, struct poll_table_struct *wait) 1275{ 1276 struct ucma_file *file = filp->private_data; 1277 unsigned int mask = 0; 1278 1279 poll_wait(filp, &file->poll_wait, wait); 1280 1281 if (!list_empty(&file->event_list)) 1282 mask = POLLIN | POLLRDNORM; 1283 1284 return mask; 1285} 1286 1287/* 1288 * ucma_open() does not need the BKL: 1289 * 1290 * - no global state is referred to; 1291 * - there is no ioctl method to race against; 1292 * - no further module initialization is required for open to work 1293 * after the device is registered. 1294 */ 1295static int ucma_open(struct inode *inode, struct file *filp) 1296{ 1297 struct ucma_file *file; 1298 1299 file = kmalloc(sizeof *file, GFP_KERNEL); 1300 if (!file) 1301 return -ENOMEM; 1302 1303 INIT_LIST_HEAD(&file->event_list); 1304 INIT_LIST_HEAD(&file->ctx_list); 1305 init_waitqueue_head(&file->poll_wait); 1306 mutex_init(&file->mut); 1307 1308 filp->private_data = file; 1309 file->filp = filp; 1310 1311 return nonseekable_open(inode, filp); 1312} 1313 1314static int ucma_close(struct inode *inode, struct file *filp) 1315{ 1316 struct ucma_file *file = filp->private_data; 1317 struct ucma_context *ctx, *tmp; 1318 1319 mutex_lock(&file->mut); 1320 list_for_each_entry_safe(ctx, tmp, &file->ctx_list, list) { 1321 mutex_unlock(&file->mut); 1322 1323 mutex_lock(&mut); 1324 idr_remove(&ctx_idr, ctx->id); 1325 mutex_unlock(&mut); 1326 1327 ucma_free_ctx(ctx); 1328 mutex_lock(&file->mut); 1329 } 1330 mutex_unlock(&file->mut); 1331 kfree(file); 1332 return 0; 1333} 1334 1335static const struct file_operations ucma_fops = { 1336 .owner = THIS_MODULE, 1337 .open = ucma_open, 1338 .release = ucma_close, 1339 .write = ucma_write, 1340 .poll = ucma_poll, 1341 .llseek = no_llseek, 1342}; 1343 1344static struct miscdevice ucma_misc = { 1345 .minor = MISC_DYNAMIC_MINOR, 1346 .name = "rdma_cm", 1347 .nodename = "infiniband/rdma_cm", 1348 .mode = 0666, 1349 .fops = &ucma_fops, 1350}; 1351 1352static ssize_t show_abi_version(struct device *dev, 1353 struct device_attribute *attr, 1354 char *buf) 1355{ 1356 return sprintf(buf, "%d\n", RDMA_USER_CM_ABI_VERSION); 1357} 1358static DEVICE_ATTR(abi_version, S_IRUGO, show_abi_version, NULL); 1359 1360static int __init ucma_init(void) 1361{ 1362 int ret; 1363 1364 ret = misc_register(&ucma_misc); 1365 if (ret) 1366 return ret; 1367 1368 ret = device_create_file(ucma_misc.this_device, &dev_attr_abi_version); 1369 if (ret) { 1370 printk(KERN_ERR "rdma_ucm: couldn't create abi_version attr\n"); 1371 goto err1; 1372 } 1373 1374 ucma_ctl_table_hdr = register_net_sysctl(&init_net, "net/rdma_ucm", ucma_ctl_table); 1375 if (!ucma_ctl_table_hdr) { 1376 printk(KERN_ERR "rdma_ucm: couldn't register sysctl paths\n"); 1377 ret = -ENOMEM; 1378 goto err2; 1379 } 1380 return 0; 1381err2: 1382 device_remove_file(ucma_misc.this_device, &dev_attr_abi_version); 1383err1: 1384 misc_deregister(&ucma_misc); 1385 return ret; 1386} 1387 1388static void __exit ucma_cleanup(void) 1389{ 1390 unregister_net_sysctl_table(ucma_ctl_table_hdr); 1391 device_remove_file(ucma_misc.this_device, &dev_attr_abi_version); 1392 misc_deregister(&ucma_misc); 1393 idr_destroy(&ctx_idr); 1394} 1395 1396module_init(ucma_init); 1397module_exit(ucma_cleanup);