aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/fbmem.c
diff options
context:
space:
mode:
authorAndrea Righi <righi.andrea@gmail.com>2009-04-13 17:39:39 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-13 18:04:28 -0400
commit513adb58685615b0b1d47a3f0d40f5352beff189 (patch)
tree80afe08d17f24bbf3d5ad48d62df2e143d00ae95 /drivers/video/fbmem.c
parentb52bb3712a64c404846f30300b339cfd01e316be (diff)
fbdev: fix info->lock deadlock in fbcon_event_notify()
fb_notifier_call_chain() is called with info->lock held, i.e. in do_fb_ioctl() => FBIOPUT_VSCREENINFO => fb_set_var() and the some notifier callbacks, like fbcon_event_notify(), try to re-acquire info->lock again. Remove the lock/unlock_fb_info() in all the framebuffer notifier callbacks' and be sure to always call fb_notifier_call_chain() with info->lock held. Reported-by: Pavel Roskin <proski@gnu.org> Reported-by: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Andrea Righi <righi.andrea@gmail.com> Cc: Stefan Richter <stefanr@s5r6.in-berlin.de> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Cc: Geert Uytterhoeven <geert@linux-m68k.org> Cc: "Rafael J. Wysocki" <rjw@sisk.pl> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/fbmem.c')
-rw-r--r--drivers/video/fbmem.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c
index 2ac32e6b5953..d412a1ddc12f 100644
--- a/drivers/video/fbmem.c
+++ b/drivers/video/fbmem.c
@@ -1097,8 +1097,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1097 return -EINVAL; 1097 return -EINVAL;
1098 con2fb.framebuffer = -1; 1098 con2fb.framebuffer = -1;
1099 event.data = &con2fb; 1099 event.data = &con2fb;
1100 if (!lock_fb_info(info))
1101 return -ENODEV;
1100 event.info = info; 1102 event.info = info;
1101 fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); 1103 fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);
1104 unlock_fb_info(info);
1102 ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; 1105 ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;
1103 break; 1106 break;
1104 case FBIOPUT_CON2FBMAP: 1107 case FBIOPUT_CON2FBMAP:
@@ -1115,8 +1118,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,
1115 break; 1118 break;
1116 } 1119 }
1117 event.data = &con2fb; 1120 event.data = &con2fb;
1121 if (!lock_fb_info(info))
1122 return -ENODEV;
1118 event.info = info; 1123 event.info = info;
1119 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); 1124 ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);
1125 unlock_fb_info(info);
1120 break; 1126 break;
1121 case FBIOBLANK: 1127 case FBIOBLANK:
1122 if (!lock_fb_info(info)) 1128 if (!lock_fb_info(info))
@@ -1521,7 +1527,10 @@ register_framebuffer(struct fb_info *fb_info)
1521 registered_fb[i] = fb_info; 1527 registered_fb[i] = fb_info;
1522 1528
1523 event.info = fb_info; 1529 event.info = fb_info;
1530 if (!lock_fb_info(fb_info))
1531 return -ENODEV;
1524 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); 1532 fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
1533 unlock_fb_info(fb_info);
1525 return 0; 1534 return 0;
1526} 1535}
1527 1536
@@ -1555,8 +1564,12 @@ unregister_framebuffer(struct fb_info *fb_info)
1555 goto done; 1564 goto done;
1556 } 1565 }
1557 1566
1567
1568 if (!lock_fb_info(fb_info))
1569 return -ENODEV;
1558 event.info = fb_info; 1570 event.info = fb_info;
1559 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); 1571 ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
1572 unlock_fb_info(fb_info);
1560 1573
1561 if (ret) { 1574 if (ret) {
1562 ret = -EINVAL; 1575 ret = -EINVAL;
@@ -1590,6 +1603,8 @@ void fb_set_suspend(struct fb_info *info, int state)
1590{ 1603{
1591 struct fb_event event; 1604 struct fb_event event;
1592 1605
1606 if (!lock_fb_info(info))
1607 return;
1593 event.info = info; 1608 event.info = info;
1594 if (state) { 1609 if (state) {
1595 fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); 1610 fb_notifier_call_chain(FB_EVENT_SUSPEND, &event);
@@ -1598,6 +1613,7 @@ void fb_set_suspend(struct fb_info *info, int state)
1598 info->state = FBINFO_STATE_RUNNING; 1613 info->state = FBINFO_STATE_RUNNING;
1599 fb_notifier_call_chain(FB_EVENT_RESUME, &event); 1614 fb_notifier_call_chain(FB_EVENT_RESUME, &event);
1600 } 1615 }
1616 unlock_fb_info(info);
1601} 1617}
1602 1618
1603/** 1619/**
@@ -1667,8 +1683,11 @@ int fb_new_modelist(struct fb_info *info)
1667 err = 1; 1683 err = 1;
1668 1684
1669 if (!list_empty(&info->modelist)) { 1685 if (!list_empty(&info->modelist)) {
1686 if (!lock_fb_info(info))
1687 return -ENODEV;
1670 event.info = info; 1688 event.info = info;
1671 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); 1689 err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
1690 unlock_fb_info(info);
1672 } 1691 }
1673 1692
1674 return err; 1693 return err;