diff options
| -rw-r--r-- | drivers/infiniband/core/user_mad.c | 80 |
1 files changed, 64 insertions, 16 deletions
diff --git a/drivers/infiniband/core/user_mad.c b/drivers/infiniband/core/user_mad.c index 97128e25f78b..aed5ca23fb22 100644 --- a/drivers/infiniband/core/user_mad.c +++ b/drivers/infiniband/core/user_mad.c | |||
| @@ -94,6 +94,9 @@ struct ib_umad_port { | |||
| 94 | struct class_device *sm_class_dev; | 94 | struct class_device *sm_class_dev; |
| 95 | struct semaphore sm_sem; | 95 | struct semaphore sm_sem; |
| 96 | 96 | ||
| 97 | struct rw_semaphore mutex; | ||
| 98 | struct list_head file_list; | ||
| 99 | |||
| 97 | struct ib_device *ib_dev; | 100 | struct ib_device *ib_dev; |
| 98 | struct ib_umad_device *umad_dev; | 101 | struct ib_umad_device *umad_dev; |
| 99 | int dev_num; | 102 | int dev_num; |
| @@ -108,10 +111,10 @@ struct ib_umad_device { | |||
| 108 | 111 | ||
| 109 | struct ib_umad_file { | 112 | struct ib_umad_file { |
| 110 | struct ib_umad_port *port; | 113 | struct ib_umad_port *port; |
| 111 | spinlock_t recv_lock; | ||
| 112 | struct list_head recv_list; | 114 | struct list_head recv_list; |
| 115 | struct list_head port_list; | ||
| 116 | spinlock_t recv_lock; | ||
| 113 | wait_queue_head_t recv_wait; | 117 | wait_queue_head_t recv_wait; |
| 114 | struct rw_semaphore agent_mutex; | ||
| 115 | struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; | 118 | struct ib_mad_agent *agent[IB_UMAD_MAX_AGENTS]; |
| 116 | struct ib_mr *mr[IB_UMAD_MAX_AGENTS]; | 119 | struct ib_mr *mr[IB_UMAD_MAX_AGENTS]; |
| 117 | }; | 120 | }; |
| @@ -148,7 +151,7 @@ static int queue_packet(struct ib_umad_file *file, | |||
| 148 | { | 151 | { |
| 149 | int ret = 1; | 152 | int ret = 1; |
| 150 | 153 | ||
| 151 | down_read(&file->agent_mutex); | 154 | down_read(&file->port->mutex); |
| 152 | for (packet->mad.hdr.id = 0; | 155 | for (packet->mad.hdr.id = 0; |
| 153 | packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; | 156 | packet->mad.hdr.id < IB_UMAD_MAX_AGENTS; |
| 154 | packet->mad.hdr.id++) | 157 | packet->mad.hdr.id++) |
| @@ -161,7 +164,7 @@ static int queue_packet(struct ib_umad_file *file, | |||
| 161 | break; | 164 | break; |
| 162 | } | 165 | } |
| 163 | 166 | ||
| 164 | up_read(&file->agent_mutex); | 167 | up_read(&file->port->mutex); |
| 165 | 168 | ||
| 166 | return ret; | 169 | return ret; |
| 167 | } | 170 | } |
| @@ -322,7 +325,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
| 322 | goto err; | 325 | goto err; |
| 323 | } | 326 | } |
| 324 | 327 | ||
| 325 | down_read(&file->agent_mutex); | 328 | down_read(&file->port->mutex); |
| 326 | 329 | ||
| 327 | agent = file->agent[packet->mad.hdr.id]; | 330 | agent = file->agent[packet->mad.hdr.id]; |
| 328 | if (!agent) { | 331 | if (!agent) { |
| @@ -419,7 +422,7 @@ static ssize_t ib_umad_write(struct file *filp, const char __user *buf, | |||
| 419 | if (ret) | 422 | if (ret) |
| 420 | goto err_msg; | 423 | goto err_msg; |
| 421 | 424 | ||
| 422 | up_read(&file->agent_mutex); | 425 | up_read(&file->port->mutex); |
| 423 | 426 | ||
| 424 | return count; | 427 | return count; |
| 425 | 428 | ||
| @@ -430,7 +433,7 @@ err_ah: | |||
| 430 | ib_destroy_ah(ah); | 433 | ib_destroy_ah(ah); |
| 431 | 434 | ||
| 432 | err_up: | 435 | err_up: |
| 433 | up_read(&file->agent_mutex); | 436 | up_read(&file->port->mutex); |
| 434 | 437 | ||
| 435 | err: | 438 | err: |
| 436 | kfree(packet); | 439 | kfree(packet); |
| @@ -460,7 +463,12 @@ static int ib_umad_reg_agent(struct ib_umad_file *file, unsigned long arg) | |||
| 460 | int agent_id; | 463 | int agent_id; |
| 461 | int ret; | 464 | int ret; |
| 462 | 465 | ||
| 463 | down_write(&file->agent_mutex); | 466 | down_write(&file->port->mutex); |
| 467 | |||
| 468 | if (!file->port->ib_dev) { | ||
| 469 | ret = -EPIPE; | ||
| 470 | goto out; | ||
| 471 | } | ||
| 464 | 472 | ||
| 465 | if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { | 473 | if (copy_from_user(&ureq, (void __user *) arg, sizeof ureq)) { |
| 466 | ret = -EFAULT; | 474 | ret = -EFAULT; |
| @@ -522,7 +530,7 @@ err: | |||
| 522 | ib_unregister_mad_agent(agent); | 530 | ib_unregister_mad_agent(agent); |
| 523 | 531 | ||
| 524 | out: | 532 | out: |
| 525 | up_write(&file->agent_mutex); | 533 | up_write(&file->port->mutex); |
| 526 | return ret; | 534 | return ret; |
| 527 | } | 535 | } |
| 528 | 536 | ||
| @@ -531,7 +539,7 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | |||
| 531 | u32 id; | 539 | u32 id; |
| 532 | int ret = 0; | 540 | int ret = 0; |
| 533 | 541 | ||
| 534 | down_write(&file->agent_mutex); | 542 | down_write(&file->port->mutex); |
| 535 | 543 | ||
| 536 | if (get_user(id, (u32 __user *) arg)) { | 544 | if (get_user(id, (u32 __user *) arg)) { |
| 537 | ret = -EFAULT; | 545 | ret = -EFAULT; |
| @@ -548,7 +556,7 @@ static int ib_umad_unreg_agent(struct ib_umad_file *file, unsigned long arg) | |||
| 548 | file->agent[id] = NULL; | 556 | file->agent[id] = NULL; |
| 549 | 557 | ||
| 550 | out: | 558 | out: |
| 551 | up_write(&file->agent_mutex); | 559 | up_write(&file->port->mutex); |
| 552 | return ret; | 560 | return ret; |
| 553 | } | 561 | } |
| 554 | 562 | ||
| @@ -569,6 +577,7 @@ static int ib_umad_open(struct inode *inode, struct file *filp) | |||
| 569 | { | 577 | { |
| 570 | struct ib_umad_port *port; | 578 | struct ib_umad_port *port; |
| 571 | struct ib_umad_file *file; | 579 | struct ib_umad_file *file; |
| 580 | int ret = 0; | ||
| 572 | 581 | ||
| 573 | spin_lock(&port_lock); | 582 | spin_lock(&port_lock); |
| 574 | port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; | 583 | port = umad_port[iminor(inode) - IB_UMAD_MINOR_BASE]; |
| @@ -579,21 +588,32 @@ static int ib_umad_open(struct inode *inode, struct file *filp) | |||
| 579 | if (!port) | 588 | if (!port) |
| 580 | return -ENXIO; | 589 | return -ENXIO; |
| 581 | 590 | ||
| 591 | down_write(&port->mutex); | ||
| 592 | |||
| 593 | if (!port->ib_dev) { | ||
| 594 | ret = -ENXIO; | ||
| 595 | goto out; | ||
| 596 | } | ||
| 597 | |||
| 582 | file = kzalloc(sizeof *file, GFP_KERNEL); | 598 | file = kzalloc(sizeof *file, GFP_KERNEL); |
| 583 | if (!file) { | 599 | if (!file) { |
| 584 | kref_put(&port->umad_dev->ref, ib_umad_release_dev); | 600 | kref_put(&port->umad_dev->ref, ib_umad_release_dev); |
| 585 | return -ENOMEM; | 601 | ret = -ENOMEM; |
| 602 | goto out; | ||
| 586 | } | 603 | } |
| 587 | 604 | ||
| 588 | spin_lock_init(&file->recv_lock); | 605 | spin_lock_init(&file->recv_lock); |
| 589 | init_rwsem(&file->agent_mutex); | ||
| 590 | INIT_LIST_HEAD(&file->recv_list); | 606 | INIT_LIST_HEAD(&file->recv_list); |
| 591 | init_waitqueue_head(&file->recv_wait); | 607 | init_waitqueue_head(&file->recv_wait); |
| 592 | 608 | ||
| 593 | file->port = port; | 609 | file->port = port; |
| 594 | filp->private_data = file; | 610 | filp->private_data = file; |
| 595 | 611 | ||
| 596 | return 0; | 612 | list_add_tail(&file->port_list, &port->file_list); |
| 613 | |||
| 614 | out: | ||
| 615 | up_write(&port->mutex); | ||
| 616 | return ret; | ||
| 597 | } | 617 | } |
| 598 | 618 | ||
| 599 | static int ib_umad_close(struct inode *inode, struct file *filp) | 619 | static int ib_umad_close(struct inode *inode, struct file *filp) |
| @@ -603,6 +623,7 @@ static int ib_umad_close(struct inode *inode, struct file *filp) | |||
| 603 | struct ib_umad_packet *packet, *tmp; | 623 | struct ib_umad_packet *packet, *tmp; |
| 604 | int i; | 624 | int i; |
| 605 | 625 | ||
| 626 | down_write(&file->port->mutex); | ||
| 606 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) | 627 | for (i = 0; i < IB_UMAD_MAX_AGENTS; ++i) |
| 607 | if (file->agent[i]) { | 628 | if (file->agent[i]) { |
| 608 | ib_dereg_mr(file->mr[i]); | 629 | ib_dereg_mr(file->mr[i]); |
| @@ -612,6 +633,9 @@ static int ib_umad_close(struct inode *inode, struct file *filp) | |||
| 612 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) | 633 | list_for_each_entry_safe(packet, tmp, &file->recv_list, list) |
| 613 | kfree(packet); | 634 | kfree(packet); |
| 614 | 635 | ||
| 636 | list_del(&file->port_list); | ||
| 637 | up_write(&file->port->mutex); | ||
| 638 | |||
| 615 | kfree(file); | 639 | kfree(file); |
| 616 | 640 | ||
| 617 | kref_put(&dev->ref, ib_umad_release_dev); | 641 | kref_put(&dev->ref, ib_umad_release_dev); |
| @@ -680,9 +704,13 @@ static int ib_umad_sm_close(struct inode *inode, struct file *filp) | |||
| 680 | struct ib_port_modify props = { | 704 | struct ib_port_modify props = { |
| 681 | .clr_port_cap_mask = IB_PORT_SM | 705 | .clr_port_cap_mask = IB_PORT_SM |
| 682 | }; | 706 | }; |
| 683 | int ret; | 707 | int ret = 0; |
| 708 | |||
| 709 | down_write(&port->mutex); | ||
| 710 | if (port->ib_dev) | ||
| 711 | ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); | ||
| 712 | up_write(&port->mutex); | ||
| 684 | 713 | ||
| 685 | ret = ib_modify_port(port->ib_dev, port->port_num, 0, &props); | ||
| 686 | up(&port->sm_sem); | 714 | up(&port->sm_sem); |
| 687 | 715 | ||
| 688 | kref_put(&port->umad_dev->ref, ib_umad_release_dev); | 716 | kref_put(&port->umad_dev->ref, ib_umad_release_dev); |
| @@ -745,6 +773,8 @@ static int ib_umad_init_port(struct ib_device *device, int port_num, | |||
| 745 | port->ib_dev = device; | 773 | port->ib_dev = device; |
| 746 | port->port_num = port_num; | 774 | port->port_num = port_num; |
| 747 | init_MUTEX(&port->sm_sem); | 775 | init_MUTEX(&port->sm_sem); |
| 776 | init_rwsem(&port->mutex); | ||
| 777 | INIT_LIST_HEAD(&port->file_list); | ||
| 748 | 778 | ||
| 749 | port->dev = cdev_alloc(); | 779 | port->dev = cdev_alloc(); |
| 750 | if (!port->dev) | 780 | if (!port->dev) |
| @@ -813,6 +843,9 @@ err_cdev: | |||
| 813 | 843 | ||
| 814 | static void ib_umad_kill_port(struct ib_umad_port *port) | 844 | static void ib_umad_kill_port(struct ib_umad_port *port) |
| 815 | { | 845 | { |
| 846 | struct ib_umad_file *file; | ||
| 847 | int id; | ||
| 848 | |||
| 816 | class_set_devdata(port->class_dev, NULL); | 849 | class_set_devdata(port->class_dev, NULL); |
| 817 | class_set_devdata(port->sm_class_dev, NULL); | 850 | class_set_devdata(port->sm_class_dev, NULL); |
| 818 | 851 | ||
| @@ -826,6 +859,21 @@ static void ib_umad_kill_port(struct ib_umad_port *port) | |||
| 826 | umad_port[port->dev_num] = NULL; | 859 | umad_port[port->dev_num] = NULL; |
| 827 | spin_unlock(&port_lock); | 860 | spin_unlock(&port_lock); |
| 828 | 861 | ||
| 862 | down_write(&port->mutex); | ||
| 863 | |||
| 864 | port->ib_dev = NULL; | ||
| 865 | |||
| 866 | list_for_each_entry(file, &port->file_list, port_list) | ||
| 867 | for (id = 0; id < IB_UMAD_MAX_AGENTS; ++id) { | ||
| 868 | if (!file->agent[id]) | ||
| 869 | continue; | ||
| 870 | ib_dereg_mr(file->mr[id]); | ||
| 871 | ib_unregister_mad_agent(file->agent[id]); | ||
| 872 | file->agent[id] = NULL; | ||
| 873 | } | ||
| 874 | |||
| 875 | up_write(&port->mutex); | ||
| 876 | |||
| 829 | clear_bit(port->dev_num, dev_map); | 877 | clear_bit(port->dev_num, dev_map); |
| 830 | } | 878 | } |
| 831 | 879 | ||
