From aef7db4bd5a3b6068dfa05919a3d685199eed116 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 3 Oct 2008 15:23:38 -0700 Subject: fbdev: fix recursive notifier and locking when fbdev console is blanked Fix infinite recursive notifier in the fbdev layer. This causes recursive locking. Dmitry Baryshkov found the problem and confirmed that the patch fixes the bug. After doing # echo 1 > /sys/class/graphics/fb0/blank I got the following in my kernel log: ============================================= [ INFO: possible recursive locking detected ] 2.6.27-rc6-00086-gda63874-dirty #97 --------------------------------------------- echo/1564 is trying to acquire lock: ((fb_notifier_list).rwsem){..--}, at: [] __blocking_notifier_call_chain+0x38/0x6c but task is already holding lock: ((fb_notifier_list).rwsem){..--}, at: [] __blocking_notifier_call_chain+0x38/0x6c other info that might help us debug this: 2 locks held by echo/1564: #0: (&buffer->mutex){--..}, at: [] sysfs_write_file+0x30/0x80 #1: ((fb_notifier_list).rwsem){..--}, at: [] __blocking_notifier_call_chain+0x38/0x6c stack backtrace: [] (dump_stack+0x0/0x14) from [] (print_deadlock_bug+0xa4/0xd0) [] (print_deadlock_bug+0x0/0xd0) from [] (check_deadlock+0x148/0x17c) r6:c397a1e0 r5:c397a530 r4:c04fcf98 [] (check_deadlock+0x0/0x17c) from [] (validate_chain+0x3c4/0x4f0) [] (validate_chain+0x0/0x4f0) from [] (__lock_acquire+0x5e8/0x6b4) [] (__lock_acquire+0x0/0x6b4) from [] (lock_acquire+0x64/0x78) [] (lock_acquire+0x0/0x78) from [] (down_read+0x4c/0x60) r7:00000009 r6:ffffffff r5:c0427a40 r4:c005a384 [] (down_read+0x0/0x60) from [] (__blocking_notifier_call_chain+0x38/0x6c) r5:c0427a40 r4:c0427a74 [] (__blocking_notifier_call_chain+0x0/0x6c) from [] (blocking_notifier_call_chain+0x20/0x28) r8:00000009 r7:c086d640 r6:c3967940 r5:00000000 r4:c38984b8 [] (blocking_notifier_call_chain+0x0/0x28) from [] (fb_notifier_call_chain+0x1c/0x24) [] (fb_notifier_call_chain+0x0/0x24) from [] (fb_blank+0x64/0x70) [] (fb_blank+0x0/0x70) from [] (fbcon_blank+0x114/0x1bc) r5:00000001 r4:c38984b8 [] (fbcon_blank+0x0/0x1bc) from [] (do_blank_screen+0x1e0/0x2a0) [] (do_blank_screen+0x0/0x2a0) from [] (fbcon_fb_blanked+0x74/0x94) r5:c3967940 r4:00000001 [] (fbcon_fb_blanked+0x0/0x94) from [] (fbcon_event_notify+0x100/0x12c) r5:fffffffe r4:c39bc194 [] (fbcon_event_notify+0x0/0x12c) from [] (notifier_call_chain+0x38/0x7c) [] (notifier_call_chain+0x0/0x7c) from [] (__blocking_notifier_call_chain+0x54/0x6c) r8:c3b51ea0 r7:00000009 r6:ffffffff r5:c0427a40 r4:c0427a74 [] (__blocking_notifier_call_chain+0x0/0x6c) from [] (blocking_notifier_call_chain+0x20/0x28) r8:00000001 r7:c3a7e000 r6:00000000 r5:00000000 r4:c38984b8 [] (blocking_notifier_call_chain+0x0/0x28) from [] (fb_notifier_call_chain+0x1c/0x24) [] (fb_notifier_call_chain+0x0/0x24) from [] (fb_blank+0x64/0x70) [] (fb_blank+0x0/0x70) from [] (store_blank+0x54/0x7c) r5:c38984b8 r4:c3b51ec4 [] (store_blank+0x0/0x7c) from [] (dev_attr_store+0x28/0x2c) r8:00000001 r7:c042bf80 r6:c39eba10 r5:c3967c30 r4:c38e0140 [] (dev_attr_store+0x0/0x2c) from [] (flush_write_buffer+0x54/0x68) [] (flush_write_buffer+0x0/0x68) from [] (sysfs_write_file+0x58/0x80) r8:c3b51f78 r7:c3bcb070 r6:c39eba10 r5:00000001 r4:00000001 [] (sysfs_write_file+0x0/0x80) from [] (vfs_write+0xb8/0x148) [] (vfs_write+0x0/0x148) from [] (sys_write+0x44/0x70) r7:00000004 r6:c3bcb070 r5:00000000 r4:00000000 [] (sys_write+0x0/0x70) from [] (ret_fast_syscall+0x0/0x2c) r6:4001b000 r5:00000001 r4:401dc658 Signed-off-by: Krzysztof Helt Reported-by: Dmitry Baryshkov Testted-by: Dmitry Baryshkov Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- drivers/video/console/fbcon.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'drivers/video/console') diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index c6299e8a041..9cbff84b787 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2400,11 +2400,15 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) if (!fbcon_is_inactive(vc, info)) { if (ops->blank_state != blank) { + int ret = 1; + ops->blank_state = blank; fbcon_cursor(vc, blank ? CM_ERASE : CM_DRAW); ops->cursor_flash = (!blank); - if (fb_blank(info, blank)) + if (info->fbops->fb_blank) + ret = info->fbops->fb_blank(blank, info); + if (ret) fbcon_generic_blank(vc, info, blank); } -- cgit v1.2.3-70-g09d2