diff options
Diffstat (limited to 'drivers/s390/cio/ccwgroup.c')
-rw-r--r-- | drivers/s390/cio/ccwgroup.c | 84 |
1 files changed, 42 insertions, 42 deletions
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c index 97b25d68e3e7..5c567414c4bb 100644 --- a/drivers/s390/cio/ccwgroup.c +++ b/drivers/s390/cio/ccwgroup.c | |||
@@ -67,6 +67,27 @@ __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev) | |||
67 | } | 67 | } |
68 | 68 | ||
69 | /* | 69 | /* |
70 | * Remove references from ccw devices to ccw group device and from | ||
71 | * ccw group device to ccw devices. | ||
72 | */ | ||
73 | static void __ccwgroup_remove_cdev_refs(struct ccwgroup_device *gdev) | ||
74 | { | ||
75 | struct ccw_device *cdev; | ||
76 | int i; | ||
77 | |||
78 | for (i = 0; i < gdev->count; i++) { | ||
79 | cdev = gdev->cdev[i]; | ||
80 | if (!cdev) | ||
81 | continue; | ||
82 | spin_lock_irq(cdev->ccwlock); | ||
83 | dev_set_drvdata(&cdev->dev, NULL); | ||
84 | spin_unlock_irq(cdev->ccwlock); | ||
85 | gdev->cdev[i] = NULL; | ||
86 | put_device(&cdev->dev); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | /* | ||
70 | * Provide an 'ungroup' attribute so the user can remove group devices no | 91 | * Provide an 'ungroup' attribute so the user can remove group devices no |
71 | * longer needed or accidentially created. Saves memory :) | 92 | * longer needed or accidentially created. Saves memory :) |
72 | */ | 93 | */ |
@@ -78,6 +99,7 @@ static void ccwgroup_ungroup_callback(struct device *dev) | |||
78 | if (device_is_registered(&gdev->dev)) { | 99 | if (device_is_registered(&gdev->dev)) { |
79 | __ccwgroup_remove_symlinks(gdev); | 100 | __ccwgroup_remove_symlinks(gdev); |
80 | device_unregister(dev); | 101 | device_unregister(dev); |
102 | __ccwgroup_remove_cdev_refs(gdev); | ||
81 | } | 103 | } |
82 | mutex_unlock(&gdev->reg_mutex); | 104 | mutex_unlock(&gdev->reg_mutex); |
83 | } | 105 | } |
@@ -116,21 +138,7 @@ static DEVICE_ATTR(ungroup, 0200, NULL, ccwgroup_ungroup_store); | |||
116 | static void | 138 | static void |
117 | ccwgroup_release (struct device *dev) | 139 | ccwgroup_release (struct device *dev) |
118 | { | 140 | { |
119 | struct ccwgroup_device *gdev; | 141 | kfree(to_ccwgroupdev(dev)); |
120 | int i; | ||
121 | |||
122 | gdev = to_ccwgroupdev(dev); | ||
123 | |||
124 | for (i = 0; i < gdev->count; i++) { | ||
125 | if (gdev->cdev[i]) { | ||
126 | spin_lock_irq(gdev->cdev[i]->ccwlock); | ||
127 | if (dev_get_drvdata(&gdev->cdev[i]->dev) == gdev) | ||
128 | dev_set_drvdata(&gdev->cdev[i]->dev, NULL); | ||
129 | spin_unlock_irq(gdev->cdev[i]->ccwlock); | ||
130 | put_device(&gdev->cdev[i]->dev); | ||
131 | } | ||
132 | } | ||
133 | kfree(gdev); | ||
134 | } | 142 | } |
135 | 143 | ||
136 | static int | 144 | static int |
@@ -420,7 +428,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
420 | gdev = to_ccwgroupdev(dev); | 428 | gdev = to_ccwgroupdev(dev); |
421 | gdrv = to_ccwgroupdrv(dev->driver); | 429 | gdrv = to_ccwgroupdrv(dev->driver); |
422 | 430 | ||
423 | if (!try_module_get(gdrv->owner)) | 431 | if (!try_module_get(gdrv->driver.owner)) |
424 | return -EINVAL; | 432 | return -EINVAL; |
425 | 433 | ||
426 | ret = strict_strtoul(buf, 0, &value); | 434 | ret = strict_strtoul(buf, 0, &value); |
@@ -434,7 +442,7 @@ ccwgroup_online_store (struct device *dev, struct device_attribute *attr, const | |||
434 | else | 442 | else |
435 | ret = -EINVAL; | 443 | ret = -EINVAL; |
436 | out: | 444 | out: |
437 | module_put(gdrv->owner); | 445 | module_put(gdrv->driver.owner); |
438 | return (ret == 0) ? count : ret; | 446 | return (ret == 0) ? count : ret; |
439 | } | 447 | } |
440 | 448 | ||
@@ -608,8 +616,6 @@ int ccwgroup_driver_register(struct ccwgroup_driver *cdriver) | |||
608 | { | 616 | { |
609 | /* register our new driver with the core */ | 617 | /* register our new driver with the core */ |
610 | cdriver->driver.bus = &ccwgroup_bus_type; | 618 | cdriver->driver.bus = &ccwgroup_bus_type; |
611 | cdriver->driver.name = cdriver->name; | ||
612 | cdriver->driver.owner = cdriver->owner; | ||
613 | 619 | ||
614 | return driver_register(&cdriver->driver); | 620 | return driver_register(&cdriver->driver); |
615 | } | 621 | } |
@@ -639,6 +645,7 @@ void ccwgroup_driver_unregister(struct ccwgroup_driver *cdriver) | |||
639 | mutex_lock(&gdev->reg_mutex); | 645 | mutex_lock(&gdev->reg_mutex); |
640 | __ccwgroup_remove_symlinks(gdev); | 646 | __ccwgroup_remove_symlinks(gdev); |
641 | device_unregister(dev); | 647 | device_unregister(dev); |
648 | __ccwgroup_remove_cdev_refs(gdev); | ||
642 | mutex_unlock(&gdev->reg_mutex); | 649 | mutex_unlock(&gdev->reg_mutex); |
643 | put_device(dev); | 650 | put_device(dev); |
644 | } | 651 | } |
@@ -660,25 +667,6 @@ int ccwgroup_probe_ccwdev(struct ccw_device *cdev) | |||
660 | return 0; | 667 | return 0; |
661 | } | 668 | } |
662 | 669 | ||
663 | static struct ccwgroup_device * | ||
664 | __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev) | ||
665 | { | ||
666 | struct ccwgroup_device *gdev; | ||
667 | |||
668 | gdev = dev_get_drvdata(&cdev->dev); | ||
669 | if (gdev) { | ||
670 | if (get_device(&gdev->dev)) { | ||
671 | mutex_lock(&gdev->reg_mutex); | ||
672 | if (device_is_registered(&gdev->dev)) | ||
673 | return gdev; | ||
674 | mutex_unlock(&gdev->reg_mutex); | ||
675 | put_device(&gdev->dev); | ||
676 | } | ||
677 | return NULL; | ||
678 | } | ||
679 | return NULL; | ||
680 | } | ||
681 | |||
682 | /** | 670 | /** |
683 | * ccwgroup_remove_ccwdev() - remove function for slave devices | 671 | * ccwgroup_remove_ccwdev() - remove function for slave devices |
684 | * @cdev: ccw device to be removed | 672 | * @cdev: ccw device to be removed |
@@ -694,13 +682,25 @@ void ccwgroup_remove_ccwdev(struct ccw_device *cdev) | |||
694 | /* Ignore offlining errors, device is gone anyway. */ | 682 | /* Ignore offlining errors, device is gone anyway. */ |
695 | ccw_device_set_offline(cdev); | 683 | ccw_device_set_offline(cdev); |
696 | /* If one of its devices is gone, the whole group is done for. */ | 684 | /* If one of its devices is gone, the whole group is done for. */ |
697 | gdev = __ccwgroup_get_gdev_by_cdev(cdev); | 685 | spin_lock_irq(cdev->ccwlock); |
698 | if (gdev) { | 686 | gdev = dev_get_drvdata(&cdev->dev); |
687 | if (!gdev) { | ||
688 | spin_unlock_irq(cdev->ccwlock); | ||
689 | return; | ||
690 | } | ||
691 | /* Get ccwgroup device reference for local processing. */ | ||
692 | get_device(&gdev->dev); | ||
693 | spin_unlock_irq(cdev->ccwlock); | ||
694 | /* Unregister group device. */ | ||
695 | mutex_lock(&gdev->reg_mutex); | ||
696 | if (device_is_registered(&gdev->dev)) { | ||
699 | __ccwgroup_remove_symlinks(gdev); | 697 | __ccwgroup_remove_symlinks(gdev); |
700 | device_unregister(&gdev->dev); | 698 | device_unregister(&gdev->dev); |
701 | mutex_unlock(&gdev->reg_mutex); | 699 | __ccwgroup_remove_cdev_refs(gdev); |
702 | put_device(&gdev->dev); | ||
703 | } | 700 | } |
701 | mutex_unlock(&gdev->reg_mutex); | ||
702 | /* Release ccwgroup device reference for local processing. */ | ||
703 | put_device(&gdev->dev); | ||
704 | } | 704 | } |
705 | 705 | ||
706 | MODULE_LICENSE("GPL"); | 706 | MODULE_LICENSE("GPL"); |