9df5808cca
The i915_vblank_swap() function schedules an automatic buffer swap upon receipt of the vertical sync interrupt. Such an operation is lengthy so it can't be allowed to happen in normal interrupt context, thus the DRM implements this by scheduling the work in a kernel softirq-scheduled tasklet. In order for the buffer swap to work safely, the DRM's central lock must be taken, via a call to drm_lock_take() located in drivers/char/drm/drm_irq.c within the function drm_locked_tasklet_func(). The lock-taking logic uses a non-interrupt-blocking spinlock to implement the manipulations needed to take the lock. This semantic would be safe if all attempts to use the spinlock only happen from process context. However this buffer swap happens from softirq context which is really a form of interrupt context. Thus we have an unsafe situation, in that drm_locked_tasklet_func() can block on a spinlock already taken by a thread in process context which will never get scheduled again because of the blocked softirq tasklet. This wedges the kernel hard. To trigger this bug, run a dual-head cloned mode configuration which uses the i915 drm, then execute an opengl application which synchronizes buffer swaps against the vertical sync interrupt. In my testing, a lockup always results after running anywhere from 5 minutes to an hour and a half. I believe dual-head is needed to really trigger the problem because then the vertical sync interrupt handling is no longer predictable (due to being interrupt-sourced from two different heads running at different speeds). This raises the probability of the tasklet trying to run while the userspace DRI is doing things to the GPU (and manipulating the DRM lock). The fix is to change the relevant spinlock semantics to be the interrupt-blocking form. After this change I am no longer able to trigger the lockup; the longest test run so far was 20 hours (test stopped after that point). Note: I have examined the places where this spinlock is being employed; all are reasonably short bounded sequences and should be suitable for interrupts being blocked without impacting overall kernel interrupt response latency. Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Dave Airlie <airlied@redhat.com> |
||
---|---|---|
.. | ||
ati_pcigart.c | ||
drm.h | ||
drm_agpsupport.c | ||
drm_auth.c | ||
drm_bufs.c | ||
drm_context.c | ||
drm_core.h | ||
drm_dma.c | ||
drm_drawable.c | ||
drm_drv.c | ||
drm_fops.c | ||
drm_hashtab.c | ||
drm_hashtab.h | ||
drm_ioc32.c | ||
drm_ioctl.c | ||
drm_irq.c | ||
drm_lock.c | ||
drm_memory.c | ||
drm_memory.h | ||
drm_memory_debug.h | ||
drm_mm.c | ||
drm_os_linux.h | ||
drm_pci.c | ||
drm_pciids.h | ||
drm_proc.c | ||
drm_sarea.h | ||
drm_scatter.c | ||
drm_sman.c | ||
drm_sman.h | ||
drm_stub.c | ||
drm_sysfs.c | ||
drm_vm.c | ||
drmP.h | ||
i810_dma.c | ||
i810_drm.h | ||
i810_drv.c | ||
i810_drv.h | ||
i830_dma.c | ||
i830_drm.h | ||
i830_drv.c | ||
i830_drv.h | ||
i830_irq.c | ||
i915_dma.c | ||
i915_drm.h | ||
i915_drv.c | ||
i915_drv.h | ||
i915_ioc32.c | ||
i915_irq.c | ||
i915_mem.c | ||
Kconfig | ||
Makefile | ||
mga_dma.c | ||
mga_drm.h | ||
mga_drv.c | ||
mga_drv.h | ||
mga_ioc32.c | ||
mga_irq.c | ||
mga_state.c | ||
mga_ucode.h | ||
mga_warp.c | ||
r128_cce.c | ||
r128_drm.h | ||
r128_drv.c | ||
r128_drv.h | ||
r128_ioc32.c | ||
r128_irq.c | ||
r128_state.c | ||
r300_cmdbuf.c | ||
r300_reg.h | ||
radeon_cp.c | ||
radeon_drm.h | ||
radeon_drv.c | ||
radeon_drv.h | ||
radeon_ioc32.c | ||
radeon_irq.c | ||
radeon_mem.c | ||
radeon_state.c | ||
README.drm | ||
savage_bci.c | ||
savage_drm.h | ||
savage_drv.c | ||
savage_drv.h | ||
savage_state.c | ||
sis_drm.h | ||
sis_drv.c | ||
sis_drv.h | ||
sis_mm.c | ||
tdfx_drv.c | ||
tdfx_drv.h | ||
via_3d_reg.h | ||
via_dma.c | ||
via_dmablit.c | ||
via_dmablit.h | ||
via_drm.h | ||
via_drv.c | ||
via_drv.h | ||
via_irq.c | ||
via_map.c | ||
via_mm.c | ||
via_verifier.c | ||
via_verifier.h | ||
via_video.c |
************************************************************ * For the very latest on DRI development, please see: * * http://dri.freedesktop.org/ * ************************************************************ The Direct Rendering Manager (drm) is a device-independent kernel-level device driver that provides support for the XFree86 Direct Rendering Infrastructure (DRI). The DRM supports the Direct Rendering Infrastructure (DRI) in four major ways: 1. The DRM provides synchronized access to the graphics hardware via the use of an optimized two-tiered lock. 2. The DRM enforces the DRI security policy for access to the graphics hardware by only allowing authenticated X11 clients access to restricted regions of memory. 3. The DRM provides a generic DMA engine, complete with multiple queues and the ability to detect the need for an OpenGL context switch. 4. The DRM is extensible via the use of small device-specific modules that rely extensively on the API exported by the DRM module. Documentation on the DRI is available from: http://dri.freedesktop.org/wiki/Documentation http://sourceforge.net/project/showfiles.php?group_id=387 http://dri.sourceforge.net/doc/ For specific information about kernel-level support, see: The Direct Rendering Manager, Kernel Support for the Direct Rendering Infrastructure http://dri.sourceforge.net/doc/drm_low_level.html Hardware Locking for the Direct Rendering Infrastructure http://dri.sourceforge.net/doc/hardware_locking_low_level.html A Security Analysis of the Direct Rendering Infrastructure http://dri.sourceforge.net/doc/security_low_level.html