[PATCH 6/9] drm/nouveau: Convert event handler list to RCU
Lockdep report [1] correctly identifies a potential deadlock between nouveau_drm_vblank_enable() and nouveau_drm_vblank_handler() due to inverted lock order of event->lock with drm core's dev->vblank_time_lock. Fix vblank event deadlock by converting event handler list to RCU. List updates remain serialized by event->lock. List traversal & handler execution is lockless which prevents inverted lock order problems with the drm core. Safe deletion of the event handler is accomplished with synchronize_rcu() for those handlers stored in nouveau_object-based containers (nouveau_drm & nv50_/nvc0_software_context); otherwise, with kfree_rcu (for nouveau_connector & uevent temporary handlers). [1] == [ INFO: possible circular locking dependency detected ] 3.10.0-0+tip-xeon+lockdep #0+tip Not tainted --- swapper/7/0 is trying to acquire lock: (&(&dev->vblank_time_lock)->rlock){-.}, at: [] drm_handle_vblank+0x69/0x400 [drm] but task is already holding lock: (&(&event->lock)->rlock){-.}, at: [] nouveau_event_trigger+0x4d/0xd0 [nouveau] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(&event->lock)->rlock){-.}: [] lock_acquire+0x92/0x1f0 [] _raw_spin_lock_irqsave+0x46/0x60 [] nouveau_event_get+0x27/0xa0 [nouveau] [] nouveau_drm_vblank_enable+0x8d/0xf0 [nouveau] [] drm_vblank_get+0xf8/0x2c0 [drm] [] drm_wait_vblank+0x84/0x6f0 [drm] [] drm_ioctl+0x559/0x690 [drm] [] do_vfs_ioctl+0x97/0x590 [] SyS_ioctl+0x91/0xb0 [] system_call_fastpath+0x16/0x1b -> #0 (&(&dev->vblank_time_lock)->rlock){-.}: [] __lock_acquire+0x1c43/0x1d30 [] lock_acquire+0x92/0x1f0 [] _raw_spin_lock_irqsave+0x46/0x60 [] drm_handle_vblank+0x69/0x400 [drm] [] nouveau_drm_vblank_handler+0x27/0x30 [nouveau] [] nouveau_event_trigger+0x90/0xd0 [nouveau] [] nv50_disp_intr+0xdd/0x230 [nouveau] [] nouveau_mc_intr+0xa1/0x100 [nouveau] [] handle_irq_event_percpu+0x6c/0x3d0 [] handle_irq_event+0x48/0x70 [] handle_fasteoi_irq+0x5a/0x100 [] handle_irq+0x22/0x40 [] do_IRQ+0x5a/0xd0 [] ret_from_intr+0x0/0x13 [] arch_cpu_idle+0x26/0x30 [] cpu_startup_entry+0xce/0x410 [] start_secondary+0x255/0x25c other info that might help us debug this: Possible unsafe locking scenario: CPU0CPU1 lock(&(&event->lock)->rlock); lock(&(&dev->vblank_time_lock)->rlock); lock(&(&event->lock)->rlock); lock(&(&dev->vblank_time_lock)->rlock); *** DEADLOCK *** 1 lock held by swapper/7/0: #0: (&(&event->lock)->rlock){-.}, at: [] nouveau_event_trigger+0x4d/0xd0 [nouveau] stack backtrace: CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.10.0-0+tip-xeon+lockdep #0+tip Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012 821ccf60 8802bfdc3b08 81755f39 8802bfdc3b58 8174f526 0002 8802bfdc3be8 8802b330a7f8 8802b330a820 8802b330a7f8 0001 Call Trace: [] dump_stack+0x19/0x1b [] print_circular_bug+0x1fb/0x20c [] __lock_acquire+0x1c43/0x1d30 [] ? trace_hardirqs_off+0xd/0x10 [] ? flat_send_IPI_mask+0x88/0xa0 [] lock_acquire+0x92/0x1f0 [] ? drm_handle_vblank+0x69/0x400 [drm] [] _raw_spin_lock_irqsave+0x46/0x60 [] ? drm_handle_vblank+0x69/0x400 [drm] [] drm_handle_vblank+0x69/0x400 [drm] [] nouveau_drm_vblank_handler+0x27/0x30 [nouveau] [] nouveau_event_trigger+0x90/0xd0 [nouveau] [] nv50_disp_intr+0xdd/0x230 [nouveau] [] ? _raw_spin_unlock_irqrestore+0x42/0x80 [] ? __hrtimer_start_range_ns+0x16c/0x530 [] nouveau_mc_intr+0xa1/0x100 [nouveau] [] handle_irq_event_percpu+0x6c/0x3d0 [] handle_irq_event+0x48/0x70 [] ? handle_fasteoi_irq+0x1e/0x100 [] handle_fasteoi_irq+0x5a/0x100 [] handle_irq+0x22/0x40 [] do_IRQ+0x5a/0xd0 [] common_interrupt+0x6f/0x6f [] ? default_idle+0x1d/0x290 [] ? default_idle+0x1b/0x290 [] arch_cpu_idle+0x26/0x30 [] cpu_startup_entry+0xce/0x410 [] ? clockevents_register_device+0xdc/0x140 [] start_secondary+0x255/0x25c Reported-by: Dave Jones Signed-off-by: Peter Hurley --- drivers/gpu/drm/nouveau/core/core/event.c | 22 +++--- .../gpu/drm/nouveau/core/engine/software/nv50.c| 1 + .../gpu/drm/nouveau/core/engine/software/nvc0.c| 1 + drivers/gpu/drm/nouveau/core/include/core/event.h | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c| 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c index 4cd1ebe..ce0a0ef 100644 --- a/drive
[PATCH 6/9] drm/nouveau: Convert event handler list to RCU
Lockdep report [1] correctly identifies a potential deadlock between nouveau_drm_vblank_enable() and nouveau_drm_vblank_handler() due to inverted lock order of event->lock with drm core's dev->vblank_time_lock. Fix vblank event deadlock by converting event handler list to RCU. List updates remain serialized by event->lock. List traversal & handler execution is lockless which prevents inverted lock order problems with the drm core. Safe deletion of the event handler is accomplished with synchronize_rcu() for those handlers stored in nouveau_object-based containers (nouveau_drm & nv50_/nvc0_software_context); otherwise, with kfree_rcu (for nouveau_connector & uevent temporary handlers). [1] == [ INFO: possible circular locking dependency detected ] 3.10.0-0+tip-xeon+lockdep #0+tip Not tainted --- swapper/7/0 is trying to acquire lock: (&(&dev->vblank_time_lock)->rlock){-.}, at: [] drm_handle_vblank+0x69/0x400 [drm] but task is already holding lock: (&(&event->lock)->rlock){-.}, at: [] nouveau_event_trigger+0x4d/0xd0 [nouveau] which lock already depends on the new lock. the existing dependency chain (in reverse order) is: -> #1 (&(&event->lock)->rlock){-.}: [] lock_acquire+0x92/0x1f0 [] _raw_spin_lock_irqsave+0x46/0x60 [] nouveau_event_get+0x27/0xa0 [nouveau] [] nouveau_drm_vblank_enable+0x8d/0xf0 [nouveau] [] drm_vblank_get+0xf8/0x2c0 [drm] [] drm_wait_vblank+0x84/0x6f0 [drm] [] drm_ioctl+0x559/0x690 [drm] [] do_vfs_ioctl+0x97/0x590 [] SyS_ioctl+0x91/0xb0 [] system_call_fastpath+0x16/0x1b -> #0 (&(&dev->vblank_time_lock)->rlock){-.}: [] __lock_acquire+0x1c43/0x1d30 [] lock_acquire+0x92/0x1f0 [] _raw_spin_lock_irqsave+0x46/0x60 [] drm_handle_vblank+0x69/0x400 [drm] [] nouveau_drm_vblank_handler+0x27/0x30 [nouveau] [] nouveau_event_trigger+0x90/0xd0 [nouveau] [] nv50_disp_intr+0xdd/0x230 [nouveau] [] nouveau_mc_intr+0xa1/0x100 [nouveau] [] handle_irq_event_percpu+0x6c/0x3d0 [] handle_irq_event+0x48/0x70 [] handle_fasteoi_irq+0x5a/0x100 [] handle_irq+0x22/0x40 [] do_IRQ+0x5a/0xd0 [] ret_from_intr+0x0/0x13 [] arch_cpu_idle+0x26/0x30 [] cpu_startup_entry+0xce/0x410 [] start_secondary+0x255/0x25c other info that might help us debug this: Possible unsafe locking scenario: CPU0CPU1 lock(&(&event->lock)->rlock); lock(&(&dev->vblank_time_lock)->rlock); lock(&(&event->lock)->rlock); lock(&(&dev->vblank_time_lock)->rlock); *** DEADLOCK *** 1 lock held by swapper/7/0: #0: (&(&event->lock)->rlock){-.}, at: [] nouveau_event_trigger+0x4d/0xd0 [nouveau] stack backtrace: CPU: 7 PID: 0 Comm: swapper/7 Not tainted 3.10.0-0+tip-xeon+lockdep #0+tip Hardware name: Dell Inc. Precision WorkStation T5400 /0RW203, BIOS A11 04/30/2012 821ccf60 8802bfdc3b08 81755f39 8802bfdc3b58 8174f526 0002 8802bfdc3be8 8802b330a7f8 8802b330a820 8802b330a7f8 0001 Call Trace: [] dump_stack+0x19/0x1b [] print_circular_bug+0x1fb/0x20c [] __lock_acquire+0x1c43/0x1d30 [] ? trace_hardirqs_off+0xd/0x10 [] ? flat_send_IPI_mask+0x88/0xa0 [] lock_acquire+0x92/0x1f0 [] ? drm_handle_vblank+0x69/0x400 [drm] [] _raw_spin_lock_irqsave+0x46/0x60 [] ? drm_handle_vblank+0x69/0x400 [drm] [] drm_handle_vblank+0x69/0x400 [drm] [] nouveau_drm_vblank_handler+0x27/0x30 [nouveau] [] nouveau_event_trigger+0x90/0xd0 [nouveau] [] nv50_disp_intr+0xdd/0x230 [nouveau] [] ? _raw_spin_unlock_irqrestore+0x42/0x80 [] ? __hrtimer_start_range_ns+0x16c/0x530 [] nouveau_mc_intr+0xa1/0x100 [nouveau] [] handle_irq_event_percpu+0x6c/0x3d0 [] handle_irq_event+0x48/0x70 [] ? handle_fasteoi_irq+0x1e/0x100 [] handle_fasteoi_irq+0x5a/0x100 [] handle_irq+0x22/0x40 [] do_IRQ+0x5a/0xd0 [] common_interrupt+0x6f/0x6f [] ? default_idle+0x1d/0x290 [] ? default_idle+0x1b/0x290 [] arch_cpu_idle+0x26/0x30 [] cpu_startup_entry+0xce/0x410 [] ? clockevents_register_device+0xdc/0x140 [] start_secondary+0x255/0x25c Reported-by: Dave Jones Signed-off-by: Peter Hurley --- drivers/gpu/drm/nouveau/core/core/event.c | 22 +++--- .../gpu/drm/nouveau/core/engine/software/nv50.c| 1 + .../gpu/drm/nouveau/core/engine/software/nvc0.c| 1 + drivers/gpu/drm/nouveau/core/include/core/event.h | 1 + drivers/gpu/drm/nouveau/nouveau_connector.c| 2 +- drivers/gpu/drm/nouveau/nouveau_drm.c | 1 + 6 files changed, 16 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c index 4cd1ebe..ce0a0ef 100644 --- a/drive