drm/i915: Remove pci private pointer after destroying the device private
authorChris Wilson <chris@chris-wilson.co.uk>
Mon, 16 Jul 2018 08:03:31 +0000 (09:03 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Mon, 16 Jul 2018 10:25:28 +0000 (11:25 +0100)
On an aborted module load, we unwind and free our device private - but
we left a dangling pointer to our privates inside the pci_device. After
the attempted aborted unload, we may still get a call to i915_pci_remove()
when the module is removed, potentially chasing stale data.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Tvrtko Ursulin <tvrtko.ursulin@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180716080332.32283-5-chris@chris-wilson.co.uk
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_pci.c

index cfa7583cf408874c21a2e236492a134e6c53cf22..337b1aad5212b01057389f2a767666151960d38f 100644 (file)
@@ -1424,6 +1424,7 @@ out_fini:
        drm_dev_fini(&dev_priv->drm);
 out_free:
        kfree(dev_priv);
+       pci_set_drvdata(pdev, NULL);
        return ret;
 }
 
index 55543f1b0236aa90d62c04241d5f55925fbd07c2..6a4d1388ad2d39b2f972e0d1e1270bab8d3ce8df 100644 (file)
@@ -674,10 +674,16 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 
 static void i915_pci_remove(struct pci_dev *pdev)
 {
-       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct drm_device *dev;
+
+       dev = pci_get_drvdata(pdev);
+       if (!dev) /* driver load aborted, nothing to cleanup */
+               return;
 
        i915_driver_unload(dev);
        drm_dev_put(dev);
+
+       pci_set_drvdata(pdev, NULL);
 }
 
 static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -712,6 +718,11 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (err)
                return err;
 
+       if (i915_inject_load_failure()) {
+               i915_pci_remove(pdev);
+               return -ENODEV;
+       }
+
        err = i915_live_selftests(pdev);
        if (err) {
                i915_pci_remove(pdev);