[PATCH] drm/gem: support BO freeing without dev->struct_mutex

Alex Deucher alexdeucher at gmail.com
Tue May 3 15:59:19 UTC 2016


On Mon, May 2, 2016 at 4:40 AM, Daniel Vetter <daniel.vetter at ffwll.ch> wrote:
> Finally all the core gem and a lot of drivers are entirely free of
> dev->struct_mutex depencies, and we can start to have an entirely
> lockless unref path.
>
> To make sure that no one who touches the core code accidentally breaks
> existing drivers which still require dev->struct_mutex I've made the
> might_lock check unconditional.
>
> While at it de-inline the ref/unref functions, they've become a bit
> too big.
>
> v2: Make it not leak like a sieve.
>
> v3: Review from Lucas:
> - drop != NULL in pointer checks.
> - fixup copypasted kerneldoc to actually match the functions.
>
> v4:
> Add __drm_gem_object_unreference as a fastpath helper for drivers who
> abolished dev->struct_mutex, requested by Chris.
>
> v5: Fix silly mistake in drm_gem_object_unreference_unlocked caught by
> intel-gfx CI - I checked for gem_free_object instead of
> gem_free_object_unlocked ...
>
> Cc: Chris Wilson <chris at chris-wilson.co.uk>
> Cc: Alex Deucher <alexdeucher at gmail.com>
> Cc: Lucas Stach <l.stach at pengutronix.de>
> Reviewed-by: Lucas Stach <l.stach at pengutronix.de> (v3)
> Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk> (v4)
> Signed-off-by: Daniel Vetter <daniel.vetter at intel.com>

Reviewed-by: Alex Deucher <alexander.deucher at amd.com>

> ---
>  drivers/gpu/drm/drm_gem.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-
>  include/drm/drmP.h        | 15 ++++++++++---
>  include/drm/drm_gem.h     | 48 +++++++++++++----------------------------
>  3 files changed, 80 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/gpu/drm/drm_gem.c b/drivers/gpu/drm/drm_gem.c
> index 25dac31eef37..973eb8805ce0 100644
> --- a/drivers/gpu/drm/drm_gem.c
> +++ b/drivers/gpu/drm/drm_gem.c
> @@ -806,12 +806,64 @@ drm_gem_object_free(struct kref *kref)
>
>         WARN_ON(!mutex_is_locked(&dev->struct_mutex));
>
> -       if (dev->driver->gem_free_object != NULL)
> +       if (dev->driver->gem_free_object_unlocked)
> +               dev->driver->gem_free_object_unlocked(obj);
> +       else if (dev->driver->gem_free_object)
>                 dev->driver->gem_free_object(obj);
>  }
>  EXPORT_SYMBOL(drm_gem_object_free);
>
>  /**
> + * drm_gem_object_unreference_unlocked - release a GEM BO reference
> + * @obj: GEM buffer object
> + *
> + * This releases a reference to @obj. Callers must not hold the
> + * dev->struct_mutex lock when calling this function.
> + *
> + * See also __drm_gem_object_unreference().
> + */
> +void
> +drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
> +{
> +       struct drm_device *dev;
> +
> +       if (!obj)
> +               return;
> +
> +       dev = obj->dev;
> +       might_lock(&dev->struct_mutex);
> +
> +       if (dev->driver->gem_free_object_unlocked)
> +               kref_put(&obj->refcount, drm_gem_object_free);
> +       else if (kref_put_mutex(&obj->refcount, drm_gem_object_free,
> +                               &dev->struct_mutex))
> +               mutex_unlock(&dev->struct_mutex);
> +}
> +EXPORT_SYMBOL(drm_gem_object_unreference_unlocked);
> +
> +/**
> + * drm_gem_object_unreference - release a GEM BO reference
> + * @obj: GEM buffer object
> + *
> + * This releases a reference to @obj. Callers must hold the dev->struct_mutex
> + * lock when calling this function, even when the driver doesn't use
> + * dev->struct_mutex for anything.
> + *
> + * For drivers not encumbered with legacy locking use
> + * drm_gem_object_unreference_unlocked() instead.
> + */
> +void
> +drm_gem_object_unreference(struct drm_gem_object *obj)
> +{
> +       if (obj) {
> +               WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> +
> +               kref_put(&obj->refcount, drm_gem_object_free);
> +       }
> +}
> +EXPORT_SYMBOL(drm_gem_object_unreference);
> +
> +/**
>   * drm_gem_vm_open - vma->ops->open implementation for GEM
>   * @vma: VM area structure
>   *
> diff --git a/include/drm/drmP.h b/include/drm/drmP.h
> index c81dd2250fc6..bd7b262d7af0 100644
> --- a/include/drm/drmP.h
> +++ b/include/drm/drmP.h
> @@ -580,12 +580,21 @@ struct drm_driver {
>         void (*debugfs_cleanup)(struct drm_minor *minor);
>
>         /**
> -        * Driver-specific constructor for drm_gem_objects, to set up
> -        * obj->driver_private.
> +        * @gem_free_object: deconstructor for drm_gem_objects
>          *
> -        * Returns 0 on success.
> +        * This is deprecated and should not be used by new drivers. Use
> +        * @gem_free_object_unlocked instead.
>          */
>         void (*gem_free_object) (struct drm_gem_object *obj);
> +
> +       /**
> +        * @gem_free_object_unlocked: deconstructor for drm_gem_objects
> +        *
> +        * This is for drivers which are not encumbered with dev->struct_mutex
> +        * legacy locking schemes. Use this hook instead of @gem_free_object.
> +        */
> +       void (*gem_free_object_unlocked) (struct drm_gem_object *obj);
> +
>         int (*gem_open_object) (struct drm_gem_object *, struct drm_file *);
>         void (*gem_close_object) (struct drm_gem_object *, struct drm_file *);
>
> diff --git a/include/drm/drm_gem.h b/include/drm/drm_gem.h
> index 0b3e11ab8757..408d6c47d98b 100644
> --- a/include/drm/drm_gem.h
> +++ b/include/drm/drm_gem.h
> @@ -200,47 +200,29 @@ drm_gem_object_reference(struct drm_gem_object *obj)
>  }
>
>  /**
> - * drm_gem_object_unreference - release a GEM BO reference
> + * __drm_gem_object_unreference - raw function to release a GEM BO reference
>   * @obj: GEM buffer object
>   *
> - * This releases a reference to @obj. Callers must hold the dev->struct_mutex
> - * lock when calling this function, even when the driver doesn't use
> - * dev->struct_mutex for anything.
> + * This function is meant to be used by drivers which are not encumbered with
> + * dev->struct_mutex legacy locking and which are using the
> + * gem_free_object_unlocked callback. It avoids all the locking checks and
> + * locking overhead of drm_gem_object_unreference() and
> + * drm_gem_object_unreference_unlocked().
>   *
> - * For drivers not encumbered with legacy locking use
> - * drm_gem_object_unreference_unlocked() instead.
> + * Drivers should never call this directly in their code. Instead they should
> + * wrap it up into a driver_gem_object_unreference(struct driver_gem_object
> + * *obj) wrapper function, and use that. Shared code should never call this, to
> + * avoid breaking drivers by accident which still depend upon dev->struct_mutex
> + * locking.
>   */
>  static inline void
> -drm_gem_object_unreference(struct drm_gem_object *obj)
> +__drm_gem_object_unreference(struct drm_gem_object *obj)
>  {
> -       if (obj != NULL) {
> -               WARN_ON(!mutex_is_locked(&obj->dev->struct_mutex));
> -
> -               kref_put(&obj->refcount, drm_gem_object_free);
> -       }
> +       kref_put(&obj->refcount, drm_gem_object_free);
>  }
>
> -/**
> - * drm_gem_object_unreference_unlocked - release a GEM BO reference
> - * @obj: GEM buffer object
> - *
> - * This releases a reference to @obj. Callers must not hold the
> - * dev->struct_mutex lock when calling this function.
> - */
> -static inline void
> -drm_gem_object_unreference_unlocked(struct drm_gem_object *obj)
> -{
> -       struct drm_device *dev;
> -
> -       if (!obj)
> -               return;
> -
> -       dev = obj->dev;
> -       if (kref_put_mutex(&obj->refcount, drm_gem_object_free, &dev->struct_mutex))
> -               mutex_unlock(&dev->struct_mutex);
> -       else
> -               might_lock(&dev->struct_mutex);
> -}
> +void drm_gem_object_unreference_unlocked(struct drm_gem_object *obj);
> +void drm_gem_object_unreference(struct drm_gem_object *obj);
>
>  int drm_gem_handle_create(struct drm_file *file_priv,
>                           struct drm_gem_object *obj,
> --
> 2.8.1
>


More information about the dri-devel mailing list