From: Dave Airlie airlied@redhat.com
Since module loading was happening under the BKL, and the drm open path took the BKL you couldn't race between them. The drm adds the sysfs node before it really probably should, i.e. before driver load has completed. Then udev creates the device node, and plymouth opens the device before we've completed loading the driver. This results in fail.
Fix this now by taking the global mutex around the driver loading procedure, which seems like the lesser of two evils patch to fix the regression.
Reported-by: Toni Spets (hifi on #radeon) Cc: Arnd Bergmann arnd@arndb.de Signed-off-by: Dave Airlie airlied@redhat.com --- drivers/gpu/drm/drm_pci.c | 4 ++++ drivers/gpu/drm/drm_platform.c | 5 +++++ 2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/drivers/gpu/drm/drm_pci.c b/drivers/gpu/drm/drm_pci.c index e20f78b..f5bd9e5 100644 --- a/drivers/gpu/drm/drm_pci.c +++ b/drivers/gpu/drm/drm_pci.c @@ -164,6 +164,8 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, dev->hose = pdev->sysdata; #endif
+ mutex_lock(&drm_global_mutex); + if ((ret = drm_fill_in_dev(dev, ent, driver))) { printk(KERN_ERR "DRM: Fill_in_dev failed.\n"); goto err_g2; @@ -199,6 +201,7 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent, driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, pci_name(pdev), dev->primary->index);
+ mutex_unlock(&drm_global_mutex); return 0;
err_g4: @@ -210,6 +213,7 @@ err_g2: pci_disable_device(pdev); err_g1: kfree(dev); + mutex_unlock(&drm_global_mutex); return ret; } EXPORT_SYMBOL(drm_get_pci_dev); diff --git a/drivers/gpu/drm/drm_platform.c b/drivers/gpu/drm/drm_platform.c index 460e9a3..92d1d0f 100644 --- a/drivers/gpu/drm/drm_platform.c +++ b/drivers/gpu/drm/drm_platform.c @@ -53,6 +53,8 @@ int drm_get_platform_dev(struct platform_device *platdev, dev->platformdev = platdev; dev->dev = &platdev->dev;
+ mutex_lock(&drm_global_mutex); + ret = drm_fill_in_dev(dev, NULL, driver);
if (ret) { @@ -87,6 +89,8 @@ int drm_get_platform_dev(struct platform_device *platdev,
list_add_tail(&dev->driver_item, &driver->device_list);
+ mutex_unlock(&drm_global_mutex); + DRM_INFO("Initialized %s %d.%d.%d %s on minor %d\n", driver->name, driver->major, driver->minor, driver->patchlevel, driver->date, dev->primary->index); @@ -100,6 +104,7 @@ err_g2: drm_put_minor(&dev->control); err_g1: kfree(dev); + mutex_unlock(&drm_global_mutex); return ret; } EXPORT_SYMBOL(drm_get_platform_dev);
On Tuesday 14 September 2010, Dave Airlie wrote:
Since module loading was happening under the BKL, and the drm open path took the BKL you couldn't race between them. The drm adds the sysfs node before it really probably should, i.e. before driver load has completed. Then udev creates the device node, and plymouth opens the device before we've completed loading the driver. This results in fail.
Not sure what exactly happened, the module loading code never held the BKL, at least not for a long time. My guess is that this has something to do with dcdb16740 "drm: Add support for platform devices to register as DRM devices", which also touches the code that needs the lock. Maybe that patch or mine just changed the timing to make an existing race more likely.
Your fix seems fine though. Ideally the drm_global_lock should go away eventually, since that is also just a hack that is not much better than the BKL (just more localized), but for now this seems the best solution.
Acked-by: Arnd Bergmann arnd@arndb.de
Arnd
dri-devel@lists.freedesktop.org