iommu/vt-d: Use BUS_NOTIFY_REMOVED_DEVICE in hotplug path
authorJoerg Roedel <jroedel@suse.de>
Mon, 29 Feb 2016 22:49:47 +0000 (23:49 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 9 Mar 2016 23:34:51 +0000 (15:34 -0800)
commit e6a8c9b337eed56eb481e1b4dd2180c25a1e5310 upstream.

In the PCI hotplug path of the Intel IOMMU driver, replace
the usage of the BUS_NOTIFY_DEL_DEVICE notifier, which is
executed before the driver is unbound from the device, with
BUS_NOTIFY_REMOVED_DEVICE, which runs after that.

This fixes a kernel BUG being triggered in the VT-d code
when the device driver tries to unmap DMA buffers and the
VT-d driver already destroyed all mappings.

Reported-by: Stefani Seibold <stefani@seibold.net>
Signed-off-by: Joerg Roedel <jroedel@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/iommu/dmar.c
drivers/iommu/intel-iommu.c

index 55a19e49205bcab9ad05c6d9bae05a4a6f02721a..3821c4786662a4841f9e83c33d6bd7f70cf6d53d 100644 (file)
@@ -329,7 +329,8 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
        /* Only care about add/remove events for physical functions */
        if (pdev->is_virtfn)
                return NOTIFY_DONE;
        /* Only care about add/remove events for physical functions */
        if (pdev->is_virtfn)
                return NOTIFY_DONE;
-       if (action != BUS_NOTIFY_ADD_DEVICE && action != BUS_NOTIFY_DEL_DEVICE)
+       if (action != BUS_NOTIFY_ADD_DEVICE &&
+           action != BUS_NOTIFY_REMOVED_DEVICE)
                return NOTIFY_DONE;
 
        info = dmar_alloc_pci_notify_info(pdev, action);
                return NOTIFY_DONE;
 
        info = dmar_alloc_pci_notify_info(pdev, action);
@@ -339,7 +340,7 @@ static int dmar_pci_bus_notifier(struct notifier_block *nb,
        down_write(&dmar_global_lock);
        if (action == BUS_NOTIFY_ADD_DEVICE)
                dmar_pci_bus_add_dev(info);
        down_write(&dmar_global_lock);
        if (action == BUS_NOTIFY_ADD_DEVICE)
                dmar_pci_bus_add_dev(info);
-       else if (action == BUS_NOTIFY_DEL_DEVICE)
+       else if (action == BUS_NOTIFY_REMOVED_DEVICE)
                dmar_pci_bus_del_dev(info);
        up_write(&dmar_global_lock);
 
                dmar_pci_bus_del_dev(info);
        up_write(&dmar_global_lock);
 
index 986a53e3eb96b4bb56faedfdb36b4bd658aacb99..a2e1b7f14df29cc78b625ec88455438d0fa1fe07 100644 (file)
@@ -4367,7 +4367,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
                                rmrru->devices_cnt);
                        if(ret < 0)
                                return ret;
                                rmrru->devices_cnt);
                        if(ret < 0)
                                return ret;
-               } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+               } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
                        dmar_remove_dev_scope(info, rmrr->segment,
                                rmrru->devices, rmrru->devices_cnt);
                }
                        dmar_remove_dev_scope(info, rmrr->segment,
                                rmrru->devices, rmrru->devices_cnt);
                }
@@ -4387,7 +4387,7 @@ int dmar_iommu_notify_scope_dev(struct dmar_pci_notify_info *info)
                                break;
                        else if(ret < 0)
                                return ret;
                                break;
                        else if(ret < 0)
                                return ret;
-               } else if (info->event == BUS_NOTIFY_DEL_DEVICE) {
+               } else if (info->event == BUS_NOTIFY_REMOVED_DEVICE) {
                        if (dmar_remove_dev_scope(info, atsr->segment,
                                        atsru->devices, atsru->devices_cnt))
                                break;
                        if (dmar_remove_dev_scope(info, atsr->segment,
                                        atsru->devices, atsru->devices_cnt))
                                break;