diff options
Diffstat (limited to 'drivers/gpu/drm/i915/i915_gem_userptr.c')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem_userptr.c | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c index d182058383a9..1719078c763a 100644 --- a/drivers/gpu/drm/i915/i915_gem_userptr.c +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c | |||
@@ -113,7 +113,10 @@ restart: | |||
113 | continue; | 113 | continue; |
114 | 114 | ||
115 | obj = mo->obj; | 115 | obj = mo->obj; |
116 | drm_gem_object_reference(&obj->base); | 116 | |
117 | if (!kref_get_unless_zero(&obj->base.refcount)) | ||
118 | continue; | ||
119 | |||
117 | spin_unlock(&mn->lock); | 120 | spin_unlock(&mn->lock); |
118 | 121 | ||
119 | cancel_userptr(obj); | 122 | cancel_userptr(obj); |
@@ -149,7 +152,20 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn, | |||
149 | it = interval_tree_iter_first(&mn->objects, start, end); | 152 | it = interval_tree_iter_first(&mn->objects, start, end); |
150 | if (it != NULL) { | 153 | if (it != NULL) { |
151 | obj = container_of(it, struct i915_mmu_object, it)->obj; | 154 | obj = container_of(it, struct i915_mmu_object, it)->obj; |
152 | drm_gem_object_reference(&obj->base); | 155 | |
156 | /* The mmu_object is released late when destroying the | ||
157 | * GEM object so it is entirely possible to gain a | ||
158 | * reference on an object in the process of being freed | ||
159 | * since our serialisation is via the spinlock and not | ||
160 | * the struct_mutex - and consequently use it after it | ||
161 | * is freed and then double free it. | ||
162 | */ | ||
163 | if (!kref_get_unless_zero(&obj->base.refcount)) { | ||
164 | spin_unlock(&mn->lock); | ||
165 | serial = 0; | ||
166 | continue; | ||
167 | } | ||
168 | |||
153 | serial = mn->serial; | 169 | serial = mn->serial; |
154 | } | 170 | } |
155 | spin_unlock(&mn->lock); | 171 | spin_unlock(&mn->lock); |