diff options
author | Roland Dreier <rolandd@cisco.com> | 2005-11-03 15:01:18 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2005-11-03 15:01:18 -0500 |
commit | 0c99cb6d5fe77872c5a32cff837c05f70158ce15 (patch) | |
tree | b974a31452cb645f063589262bde09b6c5b05701 | |
parent | 87cfe32375e0b69b999b59bf8287f501df3e43f7 (diff) |
[IB] umad: fix hot remove of IB devices
Fix hotplug of devices for ib_umad module: when a device goes away,
kill off all MAD agents for open files associated with that device,
and make sure that the device is not touched again after ib_umad
returns from its remove_one function.
Signed-off-by: Roland Dreier <rolandd@cisco.com>
-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 | ||