aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorGu Zheng <guz.fnst@cn.fujitsu.com>2013-11-05 05:00:57 -0500
committerTomi Valkeinen <tomi.valkeinen@ti.com>2013-11-11 08:52:59 -0500
commit3a41c5dbe8bc396a7fb16ca8739e945bb003342e (patch)
tree637757f9d320f138aa062b959b741e44fcce90ac /drivers/video
parentdeccd24f9077ccabc6b34f2e6d2f75c98b528fa1 (diff)
fb: reorder the lock sequence to fix potential dead lock
Following commits: 50e244cc79 fb: rework locking to fix lock ordering on takeover e93a9a8687 fb: Yet another band-aid for fixing lockdep mess 054430e773 fbcon: fix locking harder reworked locking to fix related lock ordering on takeover, and introduced console_lock into fbmem, but it seems that the new lock sequence(fb_info->lock ---> console_lock) is against with the one in console_callback(console_lock ---> fb_info->lock), and leads to a potential dead lock as following: [ 601.079000] ====================================================== [ 601.079000] [ INFO: possible circular locking dependency detected ] [ 601.079000] 3.11.0 #189 Not tainted [ 601.079000] ------------------------------------------------------- [ 601.079000] kworker/0:3/619 is trying to acquire lock: [ 601.079000] (&fb_info->lock){+.+.+.}, at: [<ffffffff81397566>] lock_fb_info+0x26/0x60 [ 601.079000] but task is already holding lock: [ 601.079000] (console_lock){+.+.+.}, at: [<ffffffff8141aae3>] console_callback+0x13/0x160 [ 601.079000] which lock already depends on the new lock. [ 601.079000] the existing dependency chain (in reverse order) is: [ 601.079000] -> #1 (console_lock){+.+.+.}: [ 601.079000] [<ffffffff810dc971>] lock_acquire+0xa1/0x140 [ 601.079000] [<ffffffff810c6267>] console_lock+0x77/0x80 [ 601.079000] [<ffffffff81399448>] register_framebuffer+0x1d8/0x320 [ 601.079000] [<ffffffff81cfb4c8>] efifb_probe+0x408/0x48f [ 601.079000] [<ffffffff8144a963>] platform_drv_probe+0x43/0x80 [ 601.079000] [<ffffffff8144853b>] driver_probe_device+0x8b/0x390 [ 601.079000] [<ffffffff814488eb>] __driver_attach+0xab/0xb0 [ 601.079000] [<ffffffff814463bd>] bus_for_each_dev+0x5d/0xa0 [ 601.079000] [<ffffffff81447e6e>] driver_attach+0x1e/0x20 [ 601.079000] [<ffffffff81447a07>] bus_add_driver+0x117/0x290 [ 601.079000] [<ffffffff81448fea>] driver_register+0x7a/0x170 [ 601.079000] [<ffffffff8144a10a>] __platform_driver_register+0x4a/0x50 [ 601.079000] [<ffffffff8144a12d>] platform_driver_probe+0x1d/0xb0 [ 601.079000] [<ffffffff81cfb0a1>] efifb_init+0x273/0x292 [ 601.079000] [<ffffffff81002132>] do_one_initcall+0x102/0x1c0 [ 601.079000] [<ffffffff81cb80a6>] kernel_init_freeable+0x15d/0x1ef [ 601.079000] [<ffffffff8166d2de>] kernel_init+0xe/0xf0 [ 601.079000] [<ffffffff816914ec>] ret_from_fork+0x7c/0xb0 [ 601.079000] -> #0 (&fb_info->lock){+.+.+.}: [ 601.079000] [<ffffffff810dc1d8>] __lock_acquire+0x1e18/0x1f10 [ 601.079000] [<ffffffff810dc971>] lock_acquire+0xa1/0x140 [ 601.079000] [<ffffffff816835ca>] mutex_lock_nested+0x7a/0x3b0 [ 601.079000] [<ffffffff81397566>] lock_fb_info+0x26/0x60 [ 601.079000] [<ffffffff813a4aeb>] fbcon_blank+0x29b/0x2e0 [ 601.079000] [<ffffffff81418658>] do_blank_screen+0x1d8/0x280 [ 601.079000] [<ffffffff8141ab34>] console_callback+0x64/0x160 [ 601.079000] [<ffffffff8108d855>] process_one_work+0x1f5/0x540 [ 601.079000] [<ffffffff8108e04c>] worker_thread+0x11c/0x370 [ 601.079000] [<ffffffff81095fbd>] kthread+0xed/0x100 [ 601.079000] [<ffffffff816914ec>] ret_from_fork+0x7c/0xb0 [ 601.079000] other info that might help us debug this: [ 601.079000] Possible unsafe locking scenario: [ 601.079000] CPU0 CPU1 [ 601.079000] ---- ---- [ 601.079000] lock(console_lock); [ 601.079000] lock(&fb_info->lock); [ 601.079000] lock(console_lock); [ 601.079000] lock(&fb_info->lock); [ 601.079000] *** DEADLOCK *** so we reorder the lock sequence the same as it in console_callback() to avoid this issue. And following Tomi's suggestion, fix these similar issues all in fb subsystem. Signed-off-by: Gu Zheng <guz.fnst@cn.fujitsu.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbmem.c50
-rw-r--r--drivers/video/fbsysfs.c19
-rw-r--r--drivers/video/sh_mobile_lcdcfb.c10
3 files changed, 51 insertions, 28 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index dacaf74256a3..010d19105ebc 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1108,14 +1108,16 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1108 case FBIOPUT_VSCREENINFO: 1108 case FBIOPUT_VSCREENINFO:
1109 if (copy_from_user(&var, argp, sizeof(var))) 1109 if (copy_from_user(&var, argp, sizeof(var)))
1110 return -EFAULT; 1110 return -EFAULT;
1111 if (!lock_fb_info(info))
1112 return -ENODEV;
1113 console_lock(); 1111 console_lock();
1112 if (!lock_fb_info(info)) {
1113 console_unlock();
1114 return -ENODEV;
1115 }
1114 info->flags |= FBINFO_MISC_USEREVENT; 1116 info->flags |= FBINFO_MISC_USEREVENT;
1115 ret = fb_set_var(info, &var); 1117 ret = fb_set_var(info, &var);
1116 info->flags &= ~FBINFO_MISC_USEREVENT; 1118 info->flags &= ~FBINFO_MISC_USEREVENT;
1117 console_unlock();
1118 unlock_fb_info(info); 1119 unlock_fb_info(info);
1120 console_unlock();
1119 if (!ret && copy_to_user(argp, &var, sizeof(var))) 1121 if (!ret && copy_to_user(argp, &var, sizeof(var)))
1120 ret = -EFAULT; 1122 ret = -EFAULT;
1121 break; 1123 break;
@@ -1144,12 +1146,14 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1144 case FBIOPAN_DISPLAY: 1146 case FBIOPAN_DISPLAY:
1145 if (copy_from_user(&var, argp, sizeof(var))) 1147 if (copy_from_user(&var, argp, sizeof(var)))
1146 return -EFAULT; 1148 return -EFAULT;
1147 if (!lock_fb_info(info))
1148 return -ENODEV;
1149 console_lock(); 1149 console_lock();
1150 if (!lock_fb_info(info)) {
1151 console_unlock();
1152 return -ENODEV;
1153 }
1150 ret = fb_pan_display(info, &var); 1154 ret = fb_pan_display(info, &var);
1151 console_unlock();
1152 unlock_fb_info(info); 1155 unlock_fb_info(info);
1156 console_unlock();
1153 if (ret == 0 && copy_to_user(argp, &var, sizeof(var))) 1157 if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))
1154 return -EFAULT; 1158 return -EFAULT;
1155 break; 1159 break;
@@ -1184,23 +1188,27 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1184 break; 1188 break;
1185 } 1189 }
1186 event.data = &con2fb; 1190 event.data = &con2fb;
1187 if (!lock_fb_info(info))
1188 return -ENODEV;
1189 console_lock(); 1191 console_lock();
1192 if (!lock_fb_info(info)) {
1193 console_unlock();
1194 return -ENODEV;
1195 }
1190 event.info = info; 1196 event.info = info;
1191 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); 1197 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
1192 console_unlock();
1193 unlock_fb_info(info); 1198 unlock_fb_info(info);
1199 console_unlock();
1194 break; 1200 break;
1195 case FBIOBLANK: 1201 case FBIOBLANK:
1196 if (!lock_fb_info(info))
1197 return -ENODEV;
1198 console_lock(); 1202 console_lock();
1203 if (!lock_fb_info(info)) {
1204 console_unlock();
1205 return -ENODEV;
1206 }
1199 info->flags |= FBINFO_MISC_USEREVENT; 1207 info->flags |= FBINFO_MISC_USEREVENT;
1200 ret = fb_blank(info, arg); 1208 ret = fb_blank(info, arg);
1201 info->flags &= ~FBINFO_MISC_USEREVENT; 1209 info->flags &= ~FBINFO_MISC_USEREVENT;
1202 console_unlock();
1203 unlock_fb_info(info); 1210 unlock_fb_info(info);
1211 console_unlock();
1204 break; 1212 break;
1205 default: 1213 default:
1206 if (!lock_fb_info(info)) 1214 if (!lock_fb_info(info))
@@ -1660,12 +1668,15 @@ static int do_register_framebuffer(struct fb_info *fb_info)
1660 registered_fb[i] = fb_info; 1668 registered_fb[i] = fb_info;
1661 1669
1662 event.info = fb_info; 1670 event.info = fb_info;
1663 if (!lock_fb_info(fb_info))
1664 return -ENODEV;
1665 console_lock(); 1671 console_lock();
1672 if (!lock_fb_info(fb_info)) {
1673 console_unlock();
1674 return -ENODEV;
1675 }
1676
1666 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); 1677 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1667 console_unlock();
1668 unlock_fb_info(fb_info); 1678 unlock_fb_info(fb_info);
1679 console_unlock();
1669 return 0; 1680 return 0;
1670} 1681}
1671 1682
@@ -1678,13 +1689,16 @@ static int do_unregister_framebuffer(struct fb_info *fb_info)
1678 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info) 1689 if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
1679 return -EINVAL; 1690 return -EINVAL;
1680 1691
1681 if (!lock_fb_info(fb_info))
1682 return -ENODEV;
1683 console_lock(); 1692 console_lock();
1693 if (!lock_fb_info(fb_info)) {
1694 console_unlock();
1695 return -ENODEV;
1696 }
1697
1684 event.info = fb_info; 1698 event.info = fb_info;
1685 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1699 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1686 console_unlock();
1687 unlock_fb_info(fb_info); 1700 unlock_fb_info(fb_info);
1701 console_unlock();
1688 1702
1689 if (ret) 1703 if (ret)
1690 return -EINVAL; 1704 return -EINVAL;
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index ef476b02fbe5..53444ac19fe0 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -177,9 +177,12 @@ static ssize_t store_modes(struct device *device,
177 if (i * sizeof(struct fb_videomode) != count) 177 if (i * sizeof(struct fb_videomode) != count)
178 return -EINVAL; 178 return -EINVAL;
179 179
180 if (!lock_fb_info(fb_info))
181 return -ENODEV;
182 console_lock(); 180 console_lock();
181 if (!lock_fb_info(fb_info)) {
182 console_unlock();
183 return -ENODEV;
184 }
185
183 list_splice(&fb_info->modelist, &old_list); 186 list_splice(&fb_info->modelist, &old_list);
184 fb_videomode_to_modelist((const struct fb_videomode *)buf, i, 187 fb_videomode_to_modelist((const struct fb_videomode *)buf, i,
185 &fb_info->modelist); 188 &fb_info->modelist);
@@ -189,8 +192,8 @@ static ssize_t store_modes(struct device *device,
189 } else 192 } else
190 fb_destroy_modelist(&old_list); 193 fb_destroy_modelist(&old_list);
191 194
192 console_unlock();
193 unlock_fb_info(fb_info); 195 unlock_fb_info(fb_info);
196 console_unlock();
194 197
195 return 0; 198 return 0;
196} 199}
@@ -404,12 +407,16 @@ static ssize_t store_fbstate(struct device *device,
404 407
405 state = simple_strtoul(buf, &last, 0); 408 state = simple_strtoul(buf, &last, 0);
406 409
407 if (!lock_fb_info(fb_info))
408 return -ENODEV;
409 console_lock(); 410 console_lock();
411 if (!lock_fb_info(fb_info)) {
412 console_unlock();
413 return -ENODEV;
414 }
415
410 fb_set_suspend(fb_info, (int)state); 416 fb_set_suspend(fb_info, (int)state);
411 console_unlock(); 417
412 unlock_fb_info(fb_info); 418 unlock_fb_info(fb_info);
419 console_unlock();
413 420
414 return count; 421 return count;
415} 422}
diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c
index eaeae0fd0962..ab85ad6c25ec 100644
--- a/drivers/video/sh_mobile_lcdcfb.c
+++ b/drivers/video/sh_mobile_lcdcfb.c
@@ -574,8 +574,9 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
574 switch (event) { 574 switch (event) {
575 case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT: 575 case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
576 /* HDMI plug in */ 576 /* HDMI plug in */
577 console_lock();
577 if (lock_fb_info(info)) { 578 if (lock_fb_info(info)) {
578 console_lock(); 579
579 580
580 ch->display.width = monspec->max_x * 10; 581 ch->display.width = monspec->max_x * 10;
581 ch->display.height = monspec->max_y * 10; 582 ch->display.height = monspec->max_y * 10;
@@ -594,19 +595,20 @@ static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
594 fb_set_suspend(info, 0); 595 fb_set_suspend(info, 0);
595 } 596 }
596 597
597 console_unlock(); 598
598 unlock_fb_info(info); 599 unlock_fb_info(info);
599 } 600 }
601 console_unlock();
600 break; 602 break;
601 603
602 case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT: 604 case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
603 /* HDMI disconnect */ 605 /* HDMI disconnect */
606 console_lock();
604 if (lock_fb_info(info)) { 607 if (lock_fb_info(info)) {
605 console_lock();
606 fb_set_suspend(info, 1); 608 fb_set_suspend(info, 1);
607 console_unlock();
608 unlock_fb_info(info); 609 unlock_fb_info(info);
609 } 610 }
611 console_unlock();
610 break; 612 break;
611 613
612 case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: 614 case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE: