diff options
-rw-r--r-- | drivers/ieee1394/nodemgr.c | 66 |
1 files changed, 20 insertions, 46 deletions
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 2953aebf4ef1..61307ca296ae 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c | |||
@@ -754,59 +754,33 @@ static DEFINE_MUTEX(nodemgr_serialize_remove_uds); | |||
754 | static void nodemgr_remove_uds(struct node_entry *ne) | 754 | static void nodemgr_remove_uds(struct node_entry *ne) |
755 | { | 755 | { |
756 | struct class_device *cdev; | 756 | struct class_device *cdev; |
757 | struct unit_directory *ud, **unreg; | 757 | struct unit_directory *tmp, *ud; |
758 | size_t i, count; | ||
759 | 758 | ||
760 | /* | 759 | /* Iteration over nodemgr_ud_class.children has to be protected by |
761 | * This is awkward: | ||
762 | * Iteration over nodemgr_ud_class.children has to be protected by | ||
763 | * nodemgr_ud_class.sem, but class_device_unregister() will eventually | 760 | * nodemgr_ud_class.sem, but class_device_unregister() will eventually |
764 | * take nodemgr_ud_class.sem too. Therefore store all uds to be | 761 | * take nodemgr_ud_class.sem too. Therefore pick out one ud at a time, |
765 | * unregistered in a temporary array, release the semaphore, and then | 762 | * release the semaphore, and then unregister the ud. Since this code |
766 | * unregister the uds. | 763 | * may be called from other contexts besides the knodemgrds, protect the |
767 | * | ||
768 | * Since nodemgr_remove_uds can also run in other contexts than the | ||
769 | * knodemgrds (which are currently globally serialized), protect the | ||
770 | * gap after release of the semaphore by nodemgr_serialize_remove_uds. | 764 | * gap after release of the semaphore by nodemgr_serialize_remove_uds. |
771 | */ | 765 | */ |
772 | |||
773 | mutex_lock(&nodemgr_serialize_remove_uds); | 766 | mutex_lock(&nodemgr_serialize_remove_uds); |
774 | 767 | for (;;) { | |
775 | down(&nodemgr_ud_class.sem); | 768 | ud = NULL; |
776 | count = 0; | 769 | down(&nodemgr_ud_class.sem); |
777 | list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { | 770 | list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { |
778 | ud = container_of(cdev, struct unit_directory, class_dev); | 771 | tmp = container_of(cdev, struct unit_directory, |
779 | if (ud->ne == ne) | 772 | class_dev); |
780 | count++; | 773 | if (tmp->ne == ne) { |
781 | } | 774 | ud = tmp; |
782 | if (!count) { | 775 | break; |
783 | up(&nodemgr_ud_class.sem); | 776 | } |
784 | mutex_unlock(&nodemgr_serialize_remove_uds); | ||
785 | return; | ||
786 | } | ||
787 | unreg = kcalloc(count, sizeof(*unreg), GFP_KERNEL); | ||
788 | if (!unreg) { | ||
789 | HPSB_ERR("NodeMgr: out of memory in nodemgr_remove_uds"); | ||
790 | up(&nodemgr_ud_class.sem); | ||
791 | mutex_unlock(&nodemgr_serialize_remove_uds); | ||
792 | return; | ||
793 | } | ||
794 | i = 0; | ||
795 | list_for_each_entry(cdev, &nodemgr_ud_class.children, node) { | ||
796 | ud = container_of(cdev, struct unit_directory, class_dev); | ||
797 | if (ud->ne == ne) { | ||
798 | BUG_ON(i >= count); | ||
799 | unreg[i++] = ud; | ||
800 | } | 777 | } |
778 | up(&nodemgr_ud_class.sem); | ||
779 | if (ud == NULL) | ||
780 | break; | ||
781 | class_device_unregister(&ud->class_dev); | ||
782 | device_unregister(&ud->device); | ||
801 | } | 783 | } |
802 | up(&nodemgr_ud_class.sem); | ||
803 | |||
804 | for (i = 0; i < count; i++) { | ||
805 | class_device_unregister(&unreg[i]->class_dev); | ||
806 | device_unregister(&unreg[i]->device); | ||
807 | } | ||
808 | kfree(unreg); | ||
809 | |||
810 | mutex_unlock(&nodemgr_serialize_remove_uds); | 784 | mutex_unlock(&nodemgr_serialize_remove_uds); |
811 | } | 785 | } |
812 | 786 | ||