aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ieee1394/nodemgr.c66
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);
754static void nodemgr_remove_uds(struct node_entry *ne) 754static 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