From d682289f0afa226081021633fe0e35f695e792f9 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Sat, 11 Jan 2014 12:02:50 +0000 Subject: [PATCH 2/2] drm/i915: Safely acquire the struct_mutex in our mem shrinker Under memory pressure it is important that we strive to unpin some of our objects so that their backing pages can be swapped out. However, we have to avoid recursion in struct_mutex and also make sure that we safely wait upon the device and driver. The first part is done by first using a trylock and checking for recursion, but the latter was ignored. However, we can use i915_mutex_interruptible() for a safe locking strategy that should prevent deadlocks. --- drivers/gpu/drm/i915/i915_gem.c | 46 +++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 849554db9413..7e7a0d66ab46 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c @@ -4943,6 +4943,26 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task) #endif } +static bool +i915_gem_shrinker_lock(struct drm_device *dev, bool *unlock) +{ + *unlock = true; + if (mutex_trylock(&dev->struct_mutex)) + return true; + + if (mutex_is_locked_by(&dev->struct_mutex, current)) { + if (to_i915(dev)->mm.shrinker_no_lock_stealing) + return false; + + *unlock = false; + } else { + if (i915_mutex_lock_interruptible(dev)) + return false; + } + + return true; +} + static int num_vma_bound(struct drm_i915_gem_object *obj) { struct i915_vma *vma; @@ -4965,18 +4985,11 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc) mm.inactive_shrinker); struct drm_device *dev = dev_priv->dev; struct drm_i915_gem_object *obj; - bool unlock = true; unsigned long count; + bool unlock; - if (!mutex_trylock(&dev->struct_mutex)) { - if (!mutex_is_locked_by(&dev->struct_mutex, current)) - return 0; - - if (dev_priv->mm.shrinker_no_lock_stealing) - return 0; - - unlock = false; - } + if (!i915_gem_shrinker_lock(dev, &unlock)) + return 0; count = 0; list_for_each_entry(obj, &dev_priv->mm.unbound_list, global_list) @@ -5069,17 +5082,10 @@ i915_gem_inactive_scan(struct shrinker *shrinker, struct shrink_control *sc) mm.inactive_shrinker); struct drm_device *dev = dev_priv->dev; unsigned long freed; - bool unlock = true; - - if (!mutex_trylock(&dev->struct_mutex)) { - if (!mutex_is_locked_by(&dev->struct_mutex, current)) - return SHRINK_STOP; + bool unlock; - if (dev_priv->mm.shrinker_no_lock_stealing) - return SHRINK_STOP; - - unlock = false; - } + if (!i915_gem_shrinker_lock(dev, &unlock)) + return SHRINK_STOP; freed = i915_gem_purge(dev_priv, sc->nr_to_scan); if (freed < sc->nr_to_scan) -- 1.8.5.2