]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
iommu/vt-d: fix PCI device reference leakage on error recovery path
authorJiang Liu <jiang.liu@linux.intel.com>
Mon, 6 Jan 2014 06:18:09 +0000 (14:18 +0800)
committerJoerg Roedel <joro@8bytes.org>
Thu, 9 Jan 2014 11:42:35 +0000 (12:42 +0100)
Function dmar_parse_dev_scope() should release the PCI device reference
count gained in function dmar_parse_one_dev_scope() on error recovery,
otherwise it will cause PCI device object leakage.

This patch also introduces dmar_free_dev_scope(), which will be used
to support DMAR device hotplug.

Reviewed-by: Yijing Wang <wangyijing@huawei.com>
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
Signed-off-by: Joerg Roedel <joro@8bytes.org>
drivers/iommu/dmar.c
include/linux/dmar.h

index fb35d1bd19e1012d62f3c3633674f50e8f15b1af..28d93b68ff0264b8a1c2ec6dc626f8c94784d057 100644 (file)
@@ -100,7 +100,6 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
        if (!pdev) {
                pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
                        segment, scope->bus, path->device, path->function);
-               *dev = NULL;
                return 0;
        }
        if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
@@ -151,7 +150,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
                        ret = dmar_parse_one_dev_scope(scope,
                                &(*devices)[index], segment);
                        if (ret) {
-                               kfree(*devices);
+                               dmar_free_dev_scope(devices, cnt);
                                return ret;
                        }
                        index ++;
@@ -162,6 +161,17 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
        return 0;
 }
 
+void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt)
+{
+       if (*devices && *cnt) {
+               while (--*cnt >= 0)
+                       pci_dev_put((*devices)[*cnt]);
+               kfree(*devices);
+               *devices = NULL;
+               *cnt = 0;
+       }
+}
+
 /**
  * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
  * structure which uniquely represent one DMA remapping hardware unit
index b029d1aa2d12a6d18f38f6472ef63bf44bb44568..205ee37eed73bf5ed36acd80ebb1ae4378bb156e 100644 (file)
@@ -62,6 +62,9 @@ extern struct list_head dmar_drhd_units;
 
 extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
+extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
+                               struct pci_dev ***devices, u16 segment);
+extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt);
 
 /* Intel IOMMU detection */
 extern int detect_intel_iommu(void);
@@ -157,8 +160,6 @@ struct dmar_atsr_unit {
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
-                               struct pci_dev ***devices, u16 segment);
 extern int intel_iommu_init(void);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }