diff options
author | Joerg Roedel <jroedel@suse.de> | 2015-05-28 12:41:27 -0400 |
---|---|---|
committer | Joerg Roedel <jroedel@suse.de> | 2015-06-05 09:13:10 -0400 |
commit | 8da30142a21e2d7595510892a4c99cf294f7e6f1 (patch) | |
tree | 0f1fa73de54a9165c9ae749bb829d3f9cbb302b5 | |
parent | 19762d7095e6392b6ec56c363a6f29b2119488c2 (diff) |
iommu: Clean up after a failed bus initialization
Make sure we call the ->remove_device call-back on all
devices already initialized with ->add_device when the bus
initialization fails.
Signed-off-by: Joerg Roedel <jroedel@suse.de>
-rw-r--r-- | drivers/iommu/iommu.c | 35 |
1 files changed, 26 insertions, 9 deletions
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index 9c9336a923cd..f0e0a233c902 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c | |||
@@ -753,6 +753,17 @@ static int add_iommu_group(struct device *dev, void *data) | |||
753 | return ops->add_device(dev); | 753 | return ops->add_device(dev); |
754 | } | 754 | } |
755 | 755 | ||
756 | static int remove_iommu_group(struct device *dev, void *data) | ||
757 | { | ||
758 | struct iommu_callback_data *cb = data; | ||
759 | const struct iommu_ops *ops = cb->ops; | ||
760 | |||
761 | if (ops->remove_device && dev->iommu_group) | ||
762 | ops->remove_device(dev); | ||
763 | |||
764 | return 0; | ||
765 | } | ||
766 | |||
756 | static int iommu_bus_notifier(struct notifier_block *nb, | 767 | static int iommu_bus_notifier(struct notifier_block *nb, |
757 | unsigned long action, void *data) | 768 | unsigned long action, void *data) |
758 | { | 769 | { |
@@ -821,19 +832,25 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops) | |||
821 | nb->notifier_call = iommu_bus_notifier; | 832 | nb->notifier_call = iommu_bus_notifier; |
822 | 833 | ||
823 | err = bus_register_notifier(bus, nb); | 834 | err = bus_register_notifier(bus, nb); |
824 | if (err) { | 835 | if (err) |
825 | kfree(nb); | 836 | goto out_free; |
826 | return err; | ||
827 | } | ||
828 | 837 | ||
829 | err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group); | 838 | err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group); |
830 | if (err) { | 839 | if (err) |
831 | bus_unregister_notifier(bus, nb); | 840 | goto out_err; |
832 | kfree(nb); | 841 | |
833 | return err; | ||
834 | } | ||
835 | 842 | ||
836 | return 0; | 843 | return 0; |
844 | |||
845 | out_err: | ||
846 | /* Clean up */ | ||
847 | bus_for_each_dev(bus, NULL, &cb, remove_iommu_group); | ||
848 | bus_unregister_notifier(bus, nb); | ||
849 | |||
850 | out_free: | ||
851 | kfree(nb); | ||
852 | |||
853 | return err; | ||
837 | } | 854 | } |
838 | 855 | ||
839 | /** | 856 | /** |