diff options
author | David Herrmann <dh.herrmann@gmail.com> | 2013-11-21 11:50:50 +0100 |
---|---|---|
committer | Dave Airlie <airlied@gmail.com> | 2013-11-21 12:10:00 +0100 |
commit | 760c960bd6880cf22a57c0af9ff60c96250aad39 (patch) | |
tree | fc301356c571ad9175c09b6c5bf35c31bfa58dac /drivers/gpu/drm/drm_sysfs.c | |
parent | drm/exynos: g2d: fix memory leak to userptr (diff) | |
download | linux-760c960bd6880cf22a57c0af9ff60c96250aad39.tar.xz linux-760c960bd6880cf22a57c0af9ff60c96250aad39.zip |
drm/sysfs: fix hotplug regression since lifetime changes
airlied:
The lifetime changes introduced in 5bdebb183c9702a8c57a01dff09337be3de337a6
tried to use device_create, however that led to the regression where dev->type
wasn't getting set correctly. First attempt at fixing it would have led to
a race, so this undoes the device_createa work and does it all manually
making sure the dev->type is setup before we register the device.
Signed-off-by: David Herrmann <dh.herrmann@gmail.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/drm_sysfs.c')
-rw-r--r-- | drivers/gpu/drm/drm_sysfs.c | 40 |
1 files changed, 33 insertions, 7 deletions
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c index 1a35ea53106b..bd2bca395792 100644 --- a/drivers/gpu/drm/drm_sysfs.c +++ b/drivers/gpu/drm/drm_sysfs.c @@ -489,6 +489,11 @@ void drm_sysfs_hotplug_event(struct drm_device *dev) } EXPORT_SYMBOL(drm_sysfs_hotplug_event); +static void drm_sysfs_release(struct device *dev) +{ + kfree(dev); +} + /** * drm_sysfs_device_add - adds a class device to sysfs for a character driver * @dev: DRM device to be added @@ -501,6 +506,7 @@ EXPORT_SYMBOL(drm_sysfs_hotplug_event); int drm_sysfs_device_add(struct drm_minor *minor) { char *minor_str; + int r; if (minor->type == DRM_MINOR_CONTROL) minor_str = "controlD%d"; @@ -509,14 +515,34 @@ int drm_sysfs_device_add(struct drm_minor *minor) else minor_str = "card%d"; - minor->kdev = device_create(drm_class, minor->dev->dev, - MKDEV(DRM_MAJOR, minor->index), - minor, minor_str, minor->index); - if (IS_ERR(minor->kdev)) { - DRM_ERROR("device create failed %ld\n", PTR_ERR(minor->kdev)); - return PTR_ERR(minor->kdev); + minor->kdev = kzalloc(sizeof(*minor->kdev), GFP_KERNEL); + if (!minor->dev) { + r = -ENOMEM; + goto error; } + + device_initialize(minor->kdev); + minor->kdev->devt = MKDEV(DRM_MAJOR, minor->index); + minor->kdev->class = drm_class; + minor->kdev->type = &drm_sysfs_device_minor; + minor->kdev->parent = minor->dev->dev; + minor->kdev->release = drm_sysfs_release; + dev_set_drvdata(minor->kdev, minor); + + r = dev_set_name(minor->kdev, minor_str, minor->index); + if (r < 0) + goto error; + + r = device_add(minor->kdev); + if (r < 0) + goto error; + return 0; + +error: + DRM_ERROR("device create failed %d\n", r); + put_device(minor->kdev); + return r; } /** @@ -529,7 +555,7 @@ int drm_sysfs_device_add(struct drm_minor *minor) void drm_sysfs_device_remove(struct drm_minor *minor) { if (minor->kdev) - device_destroy(drm_class, MKDEV(DRM_MAJOR, minor->index)); + device_unregister(minor->kdev); minor->kdev = NULL; } |