Commit f96306f9 authored by Daniel Vetter's avatar Daniel Vetter

drm: manage drm_minor cleanup with drmm_

The cleanup here is somewhat tricky, since we can't tell apart the
allocated minor index from 0. So register a cleanup action first, and
if the index allocation fails, unregister that cleanup action again to
avoid bad mistakes.

The kdev for the minor already handles NULL, so no problem there.

Hence add drmm_remove_action() to the drm_managed library.

v2: Make pointer math around void ** consistent with what Laurent
suggested.

v3: Use drmm_add_action_or_reset and remove drmm_remove_action. Noticed
because of some questions from Thomas. This also means we need to move
the drmm_add_action_or_reset helper earlier in the series.

v4: Uh ... fix slightly embarrassing bug CI spotted.
Acked-by: default avatarThomas Zimmermann <tzimmermann@suse.de>
Reviewed-by: default avatarSam Ravnborg <sam@ravnborg.org>
Cc: Thomas Zimmermann <tzimmermann@suse.de>
Cc: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20200324203936.3330994-1-daniel.vetter@ffwll.ch
parent 2cbf7fc6
...@@ -93,13 +93,25 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev, ...@@ -93,13 +93,25 @@ static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
} }
} }
static void drm_minor_alloc_release(struct drm_device *dev, void *data)
{
struct drm_minor *minor = data;
unsigned long flags;
put_device(minor->kdev);
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
}
static int drm_minor_alloc(struct drm_device *dev, unsigned int type) static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
{ {
struct drm_minor *minor; struct drm_minor *minor;
unsigned long flags; unsigned long flags;
int r; int r;
minor = kzalloc(sizeof(*minor), GFP_KERNEL); minor = drmm_kzalloc(dev, sizeof(*minor), GFP_KERNEL);
if (!minor) if (!minor)
return -ENOMEM; return -ENOMEM;
...@@ -117,46 +129,20 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type) ...@@ -117,46 +129,20 @@ static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
idr_preload_end(); idr_preload_end();
if (r < 0) if (r < 0)
goto err_free; return r;
minor->index = r; minor->index = r;
r = drmm_add_action_or_reset(dev, drm_minor_alloc_release, minor);
if (r)
return r;
minor->kdev = drm_sysfs_minor_alloc(minor); minor->kdev = drm_sysfs_minor_alloc(minor);
if (IS_ERR(minor->kdev)) { if (IS_ERR(minor->kdev))
r = PTR_ERR(minor->kdev); return PTR_ERR(minor->kdev);
goto err_index;
}
*drm_minor_get_slot(dev, type) = minor; *drm_minor_get_slot(dev, type) = minor;
return 0; return 0;
err_index:
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
err_free:
kfree(minor);
return r;
}
static void drm_minor_free(struct drm_device *dev, unsigned int type)
{
struct drm_minor **slot, *minor;
unsigned long flags;
slot = drm_minor_get_slot(dev, type);
minor = *slot;
if (!minor)
return;
put_device(minor->kdev);
spin_lock_irqsave(&drm_minor_lock, flags);
idr_remove(&drm_minors_idr, minor->index);
spin_unlock_irqrestore(&drm_minor_lock, flags);
kfree(minor);
*slot = NULL;
} }
static int drm_minor_register(struct drm_device *dev, unsigned int type) static int drm_minor_register(struct drm_device *dev, unsigned int type)
...@@ -678,16 +664,16 @@ int drm_dev_init(struct drm_device *dev, ...@@ -678,16 +664,16 @@ int drm_dev_init(struct drm_device *dev,
if (drm_core_check_feature(dev, DRIVER_RENDER)) { if (drm_core_check_feature(dev, DRIVER_RENDER)) {
ret = drm_minor_alloc(dev, DRM_MINOR_RENDER); ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
if (ret) if (ret)
goto err_minors; goto err;
} }
ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY); ret = drm_minor_alloc(dev, DRM_MINOR_PRIMARY);
if (ret) if (ret)
goto err_minors; goto err;
ret = drm_legacy_create_map_hash(dev); ret = drm_legacy_create_map_hash(dev);
if (ret) if (ret)
goto err_minors; goto err;
drm_legacy_ctxbitmap_init(dev); drm_legacy_ctxbitmap_init(dev);
...@@ -695,7 +681,7 @@ int drm_dev_init(struct drm_device *dev, ...@@ -695,7 +681,7 @@ int drm_dev_init(struct drm_device *dev,
ret = drm_gem_init(dev); ret = drm_gem_init(dev);
if (ret) { if (ret) {
DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n"); DRM_ERROR("Cannot initialize graphics execution manager (GEM)\n");
goto err_ctxbitmap; goto err;
} }
} }
...@@ -708,10 +694,6 @@ int drm_dev_init(struct drm_device *dev, ...@@ -708,10 +694,6 @@ int drm_dev_init(struct drm_device *dev,
err_setunique: err_setunique:
if (drm_core_check_feature(dev, DRIVER_GEM)) if (drm_core_check_feature(dev, DRIVER_GEM))
drm_gem_destroy(dev); drm_gem_destroy(dev);
err_ctxbitmap:
err_minors:
drm_minor_free(dev, DRM_MINOR_PRIMARY);
drm_minor_free(dev, DRM_MINOR_RENDER);
err: err:
drm_managed_release(dev); drm_managed_release(dev);
...@@ -776,9 +758,6 @@ void drm_dev_fini(struct drm_device *dev) ...@@ -776,9 +758,6 @@ void drm_dev_fini(struct drm_device *dev)
if (drm_core_check_feature(dev, DRIVER_GEM)) if (drm_core_check_feature(dev, DRIVER_GEM))
drm_gem_destroy(dev); drm_gem_destroy(dev);
drm_minor_free(dev, DRM_MINOR_PRIMARY);
drm_minor_free(dev, DRM_MINOR_RENDER);
} }
EXPORT_SYMBOL(drm_dev_fini); EXPORT_SYMBOL(drm_dev_fini);
......
...@@ -149,6 +149,20 @@ int __drmm_add_action(struct drm_device *dev, ...@@ -149,6 +149,20 @@ int __drmm_add_action(struct drm_device *dev,
} }
EXPORT_SYMBOL(__drmm_add_action); EXPORT_SYMBOL(__drmm_add_action);
int __drmm_add_action_or_reset(struct drm_device *dev,
drmres_release_t action,
void *data, const char *name)
{
int ret;
ret = __drmm_add_action(dev, action, data, name);
if (ret)
action(dev, data);
return ret;
}
EXPORT_SYMBOL(__drmm_add_action_or_reset);
void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp)
{ {
struct drmres *dr; struct drmres *dr;
......
...@@ -17,7 +17,14 @@ int __must_check __drmm_add_action(struct drm_device *dev, ...@@ -17,7 +17,14 @@ int __must_check __drmm_add_action(struct drm_device *dev,
drmres_release_t action, drmres_release_t action,
void *data, const char *name); void *data, const char *name);
void drmm_add_final_kfree(struct drm_device *dev, void *parent); #define drmm_add_action_or_reset(dev, action, data) \
__drmm_add_action_or_reset(dev, action, data, #action)
int __must_check __drmm_add_action_or_reset(struct drm_device *dev,
drmres_release_t action,
void *data, const char *name);
void drmm_add_final_kfree(struct drm_device *dev, void *container);
void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) __malloc; void *drmm_kmalloc(struct drm_device *dev, size_t size, gfp_t gfp) __malloc;
static inline void *drmm_kzalloc(struct drm_device *dev, size_t size, gfp_t gfp) static inline void *drmm_kzalloc(struct drm_device *dev, size_t size, gfp_t gfp)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment