Skip to content

Commit f524a77

Browse files
icklerodrigovivi
authored andcommitted
drm/i915/gem: Hold obj->vma.lock over for_each_ggtt_vma()
While the ggtt vma are protected by their object lifetime, the list continues until it hits a non-ggtt vma, and that vma is not protected and may be freed as we inspect it. Hence, we require the obj->vma.lock to protect the list as we iterate. An example of forgetting to hold the obj->vma.lock is [1642834.464973] general protection fault, probably for non-canonical address 0xdead000000000122: 0000 [#1] SMP PTI [1642834.464977] CPU: 3 PID: 1954 Comm: Xorg Not tainted 5.6.0-300.fc32.x86_64 #1 [1642834.464979] Hardware name: LENOVO 20ARS25701/20ARS25701, BIOS GJET94WW (2.44 ) 09/14/2017 [1642834.465021] RIP: 0010:i915_gem_object_set_tiling+0x2c0/0x3e0 [i915] [1642834.465024] Code: 8b 84 24 18 01 00 00 f6 c4 80 74 59 49 8b 94 24 a0 00 00 00 49 8b 84 24 e0 00 00 00 49 8b 74 24 10 48 8b 92 30 01 00 00 89 c7 <80> ba 0a 06 00 00 03 0f 87 86 00 00 00 ba 00 00 08 00 b9 00 00 10 [1642834.465025] RSP: 0018:ffffa98780c77d60 EFLAGS: 00010282 [1642834.465028] RAX: ffff8d232bfb2578 RBX: 0000000000000002 RCX: ffff8d25873a0000 [1642834.465029] RDX: dead000000000122 RSI: fffff0af8ac6e408 RDI: 000000002bfb2578 [1642834.465030] RBP: ffff8d25873a0000 R08: ffff8d252bfb5638 R09: 0000000000000000 [1642834.465031] R10: 0000000000000000 R11: ffff8d252bfb5640 R12: ffffa987801cb8f8 [1642834.465032] R13: 0000000000001000 R14: ffff8d233e972e50 R15: ffff8d233e972d00 [1642834.465034] FS: 00007f6a3d327f00(0000) GS:ffff8d25926c0000(0000) knlGS:0000000000000000 [1642834.465036] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [1642834.465037] CR2: 00007f6a2064d000 CR3: 00000002fb57c001 CR4: 00000000001606e0 [1642834.465038] Call Trace: [1642834.465083] i915_gem_set_tiling_ioctl+0x122/0x230 [i915] [1642834.465121] ? i915_gem_object_set_tiling+0x3e0/0x3e0 [i915] [1642834.465151] drm_ioctl_kernel+0x86/0xd0 [drm] [1642834.465156] ? avc_has_perm+0x3b/0x160 [1642834.465178] drm_ioctl+0x206/0x390 [drm] [1642834.465216] ? i915_gem_object_set_tiling+0x3e0/0x3e0 [i915] [1642834.465221] ? selinux_file_ioctl+0x122/0x1c0 [1642834.465226] ? __do_munmap+0x24b/0x4d0 [1642834.465231] ksys_ioctl+0x82/0xc0 [1642834.465235] __x64_sys_ioctl+0x16/0x20 [1642834.465238] do_syscall_64+0x5b/0xf0 [1642834.465243] entry_SYSCALL_64_after_hwframe+0x44/0xa9 [1642834.465245] RIP: 0033:0x7f6a3d7b047b [1642834.465247] Code: 0f 1e fa 48 8b 05 1d aa 0c 00 64 c7 00 26 00 00 00 48 c7 c0 ff ff ff ff c3 66 0f 1f 44 00 00 f3 0f 1e fa b8 10 00 00 00 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 8b 0d ed a9 0c 00 f7 d8 64 89 01 48 [1642834.465249] RSP: 002b:00007ffe71adba28 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [1642834.465251] RAX: ffffffffffffffda RBX: 000055f99048fa40 RCX: 00007f6a3d7b047b [1642834.465253] RDX: 00007ffe71adba30 RSI: 00000000c0106461 RDI: 000000000000000e [1642834.465254] RBP: 0000000000000002 R08: 000055f98f3f1798 R09: 0000000000000002 [1642834.465255] R10: 0000000000001000 R11: 0000000000000246 R12: 0000000000000080 [1642834.465257] R13: 000055f98f3f1690 R14: 00000000c0106461 R15: 00007ffe71adba30 Now to take the spinlock during the list iteration, we need to break it down into two phases. In the first phase under the lock, we cannot sleep and so must defer the actual work to a second list, protected by the ggtt->mutex. We also need to hold the spinlock during creation of a new vma to serialise with updates of the tiling on the object. Reported-by: Dave Airlie <[email protected]> Fixes: 2850748 ("drm/i915: Pull i915_vma_pin under the vm->mutex") Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Cc: Dave Airlie <[email protected]> Cc: <[email protected]> # v5.5+ Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit cb593e5) Signed-off-by: Rodrigo Vivi <[email protected]>
1 parent 5d5e100 commit f524a77

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

drivers/gpu/drm/i915/gem/i915_gem_tiling.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,21 +182,35 @@ i915_gem_object_fence_prepare(struct drm_i915_gem_object *obj,
182182
int tiling_mode, unsigned int stride)
183183
{
184184
struct i915_ggtt *ggtt = &to_i915(obj->base.dev)->ggtt;
185-
struct i915_vma *vma;
185+
struct i915_vma *vma, *vn;
186+
LIST_HEAD(unbind);
186187
int ret = 0;
187188

188189
if (tiling_mode == I915_TILING_NONE)
189190
return 0;
190191

191192
mutex_lock(&ggtt->vm.mutex);
193+
194+
spin_lock(&obj->vma.lock);
192195
for_each_ggtt_vma(vma, obj) {
196+
GEM_BUG_ON(vma->vm != &ggtt->vm);
197+
193198
if (i915_vma_fence_prepare(vma, tiling_mode, stride))
194199
continue;
195200

201+
list_move(&vma->vm_link, &unbind);
202+
}
203+
spin_unlock(&obj->vma.lock);
204+
205+
list_for_each_entry_safe(vma, vn, &unbind, vm_link) {
196206
ret = __i915_vma_unbind(vma);
197-
if (ret)
207+
if (ret) {
208+
/* Restore the remaining vma on an error */
209+
list_splice(&unbind, &ggtt->vm.bound_list);
198210
break;
211+
}
199212
}
213+
200214
mutex_unlock(&ggtt->vm.mutex);
201215

202216
return ret;
@@ -268,6 +282,7 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
268282
}
269283
mutex_unlock(&obj->mm.lock);
270284

285+
spin_lock(&obj->vma.lock);
271286
for_each_ggtt_vma(vma, obj) {
272287
vma->fence_size =
273288
i915_gem_fence_size(i915, vma->size, tiling, stride);
@@ -278,6 +293,7 @@ i915_gem_object_set_tiling(struct drm_i915_gem_object *obj,
278293
if (vma->fence)
279294
vma->fence->dirty = true;
280295
}
296+
spin_unlock(&obj->vma.lock);
281297

282298
obj->tiling_and_stride = tiling | stride;
283299
i915_gem_object_unlock(obj);

drivers/gpu/drm/i915/i915_vma.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,16 +158,18 @@ vma_create(struct drm_i915_gem_object *obj,
158158

159159
GEM_BUG_ON(!IS_ALIGNED(vma->size, I915_GTT_PAGE_SIZE));
160160

161+
spin_lock(&obj->vma.lock);
162+
161163
if (i915_is_ggtt(vm)) {
162164
if (unlikely(overflows_type(vma->size, u32)))
163-
goto err_vma;
165+
goto err_unlock;
164166

165167
vma->fence_size = i915_gem_fence_size(vm->i915, vma->size,
166168
i915_gem_object_get_tiling(obj),
167169
i915_gem_object_get_stride(obj));
168170
if (unlikely(vma->fence_size < vma->size || /* overflow */
169171
vma->fence_size > vm->total))
170-
goto err_vma;
172+
goto err_unlock;
171173

172174
GEM_BUG_ON(!IS_ALIGNED(vma->fence_size, I915_GTT_MIN_ALIGNMENT));
173175

@@ -179,8 +181,6 @@ vma_create(struct drm_i915_gem_object *obj,
179181
__set_bit(I915_VMA_GGTT_BIT, __i915_vma_flags(vma));
180182
}
181183

182-
spin_lock(&obj->vma.lock);
183-
184184
rb = NULL;
185185
p = &obj->vma.tree.rb_node;
186186
while (*p) {
@@ -225,6 +225,8 @@ vma_create(struct drm_i915_gem_object *obj,
225225

226226
return vma;
227227

228+
err_unlock:
229+
spin_unlock(&obj->vma.lock);
228230
err_vma:
229231
i915_vma_free(vma);
230232
return ERR_PTR(-E2BIG);

0 commit comments

Comments
 (0)