diff options
author | Marcin Slusarz <marcin.slusarz@gmail.com> | 2011-03-07 06:31:35 -0500 |
---|---|---|
committer | Ben Skeggs <bskeggs@redhat.com> | 2011-03-14 02:31:45 -0400 |
commit | 7fa0cba2b269fa498804a89a0a1d763ea1f65015 (patch) | |
tree | 4acc173365b1d79ceb8d6adaa1ebc77c166648d6 /drivers/gpu/drm/nouveau/nouveau_gem.c | |
parent | b84f30e65c2352c6400b9c748b918ca4031f5d4a (diff) |
drm/nouveau: properly handle pushbuffer check failures
When "buffer in list" check does not pass, don't free validation lists - they were
not initialized yet.
Fixes this oops:
[drm] nouveau 0000:02:00.0: push 105 buffer not in list
BUG: unable to handle kernel NULL pointer dereference at 000000000000057c
IP: [<ffffffff81236aa4>] do_raw_spin_lock+0x14/0x13c
PGD 1ac6cb067 PUD 1aaa52067 PMD 0
CPU 0
Modules linked in: nouveau ttm drm_kms_helper snd_hda_codec_realtek snd_hda_intel snd_hda_codec
Pid: 6265, comm: OilRush_x86 Not tainted 2.6.38-rc6-nv+ #632 System manufacturer System Product Name/P6T SE
RIP: 0010:[<ffffffff81236aa4>] [<ffffffff81236aa4>] do_raw_spin_lock+0x14/0x13c
(...)
Process OilRush_x86 (pid: 6265, threadinfo ffff8801a6aee000, task ffff8801a26c0000)
0000000000000000 ffff8801ac74c618 0000000000000000 0000000000000578
0000000000000000 ffff8801ac74c618 0000000000000000 ffff8801bd9d0000
[<ffffffff81417f78>] _raw_spin_lock+0x1e/0x22
[<ffffffffa00a2746>] nouveau_bo_fence+0x2e/0x60 [nouveau]
[<ffffffffa00a540b>] validate_fini_list+0x35/0xeb [nouveau]
[<ffffffffa00a54d3>] validate_fini+0x12/0x31 [nouveau]
[<ffffffffa00a6386>] nouveau_gem_ioctl_pushbuf+0xe94/0xf6b [nouveau]
[<ffffffff8141ac56>] ? sub_preempt_count+0x9e/0xb2
[<ffffffff81417e94>] ? _raw_spin_unlock_irqrestore+0x30/0x4d
[<ffffffff8105dea2>] ? __wake_up+0x3f/0x48
[<ffffffff812aebb4>] drm_ioctl+0x289/0x361
[<ffffffff8141ac56>] ? sub_preempt_count+0x9e/0xb2
[<ffffffffa00a54f2>] ? nouveau_gem_ioctl_pushbuf+0x0/0xf6b [nouveau]
[<ffffffff8141ac56>] ? sub_preempt_count+0x9e/0xb2
[<ffffffffa010caa2>] nouveau_compat_ioctl+0x16/0x1c [nouveau]
[<ffffffff81142c0d>] compat_sys_ioctl+0x1c8/0x12d7
[<ffffffff814179ca>] ? trace_hardirqs_off_thunk+0x3a/0x6c
[<ffffffff81058099>] sysenter_dispatch+0x7/0x30
[<ffffffff8141798e>] ? trace_hardirqs_on_thunk+0x3a/0x3c
RIP [<ffffffff81236aa4>] do_raw_spin_lock+0x14/0x13c
RSP <ffff8801a6aefb88>
---[ end trace 0014d5d93e6147e1 ]---
Additionally, don't call validate_fini twice in case of validation failure.
Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Signed-off-by: Maarten Maathuis <madman2003@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Diffstat (limited to 'drivers/gpu/drm/nouveau/nouveau_gem.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nouveau_gem.c | 6 |
1 files changed, 4 insertions, 2 deletions
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c index 3ce58d2222cb..e8b04f4aed7e 100644 --- a/drivers/gpu/drm/nouveau/nouveau_gem.c +++ b/drivers/gpu/drm/nouveau/nouveau_gem.c | |||
@@ -600,7 +600,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
600 | if (push[i].bo_index >= req->nr_buffers) { | 600 | if (push[i].bo_index >= req->nr_buffers) { |
601 | NV_ERROR(dev, "push %d buffer not in list\n", i); | 601 | NV_ERROR(dev, "push %d buffer not in list\n", i); |
602 | ret = -EINVAL; | 602 | ret = -EINVAL; |
603 | goto out; | 603 | goto out_prevalid; |
604 | } | 604 | } |
605 | 605 | ||
606 | bo[push[i].bo_index].read_domains |= (1 << 31); | 606 | bo[push[i].bo_index].read_domains |= (1 << 31); |
@@ -612,7 +612,7 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
612 | if (ret) { | 612 | if (ret) { |
613 | if (ret != -ERESTARTSYS) | 613 | if (ret != -ERESTARTSYS) |
614 | NV_ERROR(dev, "validate: %d\n", ret); | 614 | NV_ERROR(dev, "validate: %d\n", ret); |
615 | goto out; | 615 | goto out_prevalid; |
616 | } | 616 | } |
617 | 617 | ||
618 | /* Apply any relocations that are required */ | 618 | /* Apply any relocations that are required */ |
@@ -705,6 +705,8 @@ nouveau_gem_ioctl_pushbuf(struct drm_device *dev, void *data, | |||
705 | out: | 705 | out: |
706 | validate_fini(&op, fence); | 706 | validate_fini(&op, fence); |
707 | nouveau_fence_unref(&fence); | 707 | nouveau_fence_unref(&fence); |
708 | |||
709 | out_prevalid: | ||
708 | kfree(bo); | 710 | kfree(bo); |
709 | kfree(push); | 711 | kfree(push); |
710 | 712 | ||