* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working [not found] <f17812d70904090436kd03744brca4a4bc4b85bba8@mail.gmail.com> @ 2009-04-09 12:58 ` Andrea Righi 2009-04-10 20:21 ` Krzysztof Helt 0 siblings, 1 reply; 11+ messages in thread From: Andrea Righi @ 2009-04-09 12:58 UTC (permalink / raw) To: Eric Miao Cc: LKML, Geert Uytterhoeven, Krzysztof Helt, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Stefan Richter On Thu, Apr 09, 2009 at 07:36:24PM +0800, Eric Miao wrote: > This happens on my Marvell PXA310-based Littleton platform with > Angstrom Distribution. The offending paths are many: > > FBIOPUT_VSCREENINFO: > lock_fb_info() > --> fb_set_var() > --> fb_notifier_call_chain() [FBINFO_MISC_USEREVENT] > --> fbcon_event_notifier() [FB_EVENT_MODE_CHANGE] > --> lock_fb_info() > > OK, now hang. I'd suggest a clean fix to the original assumption of > circular locking > issue and revert this commit first. > > -- > Cheers > - eric I can agree to revert 66c1ca019078220dc1bf968f2bb18421100ef147, since I don't have a clean fix for this. Pushing down fb_info->lock in fb_set_var() excluding to call fb_notifier_call_chain with fb_info->lock held doesn't seem to be so trivial... However, reverting this will re-introduce the circular locking dependency fb_info->lock => mm->mmap_sem => fb_info->lock. -Andrea ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-09 12:58 ` [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working Andrea Righi @ 2009-04-10 20:21 ` Krzysztof Helt 2009-04-10 21:16 ` Andrew Morton 2009-04-10 22:05 ` Andrea Righi 0 siblings, 2 replies; 11+ messages in thread From: Krzysztof Helt @ 2009-04-10 20:21 UTC (permalink / raw) To: Andrea Righi Cc: Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Stefan Richter On Thu, 9 Apr 2009 14:58:51 +0200 Andrea Righi <righi.andrea@gmail.com> wrote: > On Thu, Apr 09, 2009 at 07:36:24PM +0800, Eric Miao wrote: > > This happens on my Marvell PXA310-based Littleton platform with > > Angstrom Distribution. The offending paths are many: > > > > FBIOPUT_VSCREENINFO: > > lock_fb_info() > > --> fb_set_var() > > --> fb_notifier_call_chain() [FBINFO_MISC_USEREVENT] > > --> fbcon_event_notifier() [FB_EVENT_MODE_CHANGE] > > --> lock_fb_info() > > > > OK, now hang. I'd suggest a clean fix to the original assumption of > > circular locking > > issue and revert this commit first. > > > > -- > > Cheers > > - eric > > I can agree to revert 66c1ca019078220dc1bf968f2bb18421100ef147, since I > don't have a clean fix for this. Pushing down fb_info->lock in > fb_set_var() excluding to call fb_notifier_call_chain with fb_info->lock > held doesn't seem to be so trivial... > > However, reverting this will re-introduce the circular locking > dependency fb_info->lock => mm->mmap_sem => fb_info->lock. > If anybody is interested I have looked into the code of the fb_mmap() and have found that the problem Andrea tried to fix is caused only by drivers which implements their own fb_mmap(). The correct solution is to push the info->lock mutex into the fb_mmap() implemented inside the drivers. Some drivers may not need it (the ones which only calculate offsets and do not "real" iommaping). I'll try to prepare a patch after the Easters. This will require a revert of the 66c1ca commit. Happy Easters, Krzysztof ---------------------------------------------------------------------- Nagrody w jednym miejscu! Sprawdz >> http://link.interia.pl/f210b ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-10 20:21 ` Krzysztof Helt @ 2009-04-10 21:16 ` Andrew Morton 2009-04-10 22:05 ` Andrea Righi 1 sibling, 0 replies; 11+ messages in thread From: Andrew Morton @ 2009-04-10 21:16 UTC (permalink / raw) To: Krzysztof Helt Cc: adaplas, arvidjaar, hannes, linux-kernel, stefanr, geert, linux-fbdev-devel, linux-pm, harvey.harrison, righi.andrea On Fri, 10 Apr 2009 22:21:22 +0200 Krzysztof Helt <krzysztof.h1@poczta.fm> wrote: > On Thu, 9 Apr 2009 14:58:51 +0200 > Andrea Righi <righi.andrea@gmail.com> wrote: > > > On Thu, Apr 09, 2009 at 07:36:24PM +0800, Eric Miao wrote: > > > This happens on my Marvell PXA310-based Littleton platform with > > > Angstrom Distribution. The offending paths are many: > > > > > > FBIOPUT_VSCREENINFO: > > > lock_fb_info() > > > --> fb_set_var() > > > --> fb_notifier_call_chain() [FBINFO_MISC_USEREVENT] > > > --> fbcon_event_notifier() [FB_EVENT_MODE_CHANGE] > > > --> lock_fb_info() > > > > > > OK, now hang. I'd suggest a clean fix to the original assumption of > > > circular locking > > > issue and revert this commit first. > > > > > > -- > > > Cheers > > > - eric > > > > I can agree to revert 66c1ca019078220dc1bf968f2bb18421100ef147, since I > > don't have a clean fix for this. Pushing down fb_info->lock in > > fb_set_var() excluding to call fb_notifier_call_chain with fb_info->lock > > held doesn't seem to be so trivial... > > > > However, reverting this will re-introduce the circular locking > > dependency fb_info->lock => mm->mmap_sem => fb_info->lock. > > > > If anybody is interested I have looked into the code of the fb_mmap() > and have found that the problem Andrea tried to fix is caused > only by drivers which implements their own fb_mmap(). > > The correct solution is to push the info->lock mutex into > the fb_mmap() implemented inside the drivers. Some drivers > may not need it (the ones which only calculate offsets > and do not "real" iommaping). > > I'll try to prepare a patch after the Easters. Thanks. > This will require a revert > of the 66c1ca commit. yes, I'll be queueing a revert of that when I get that far through my backlog. Today or tomorrow. ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-10 20:21 ` Krzysztof Helt 2009-04-10 21:16 ` Andrew Morton @ 2009-04-10 22:05 ` Andrea Righi 2009-04-11 6:04 ` Krzysztof Helt 1 sibling, 1 reply; 11+ messages in thread From: Andrea Righi @ 2009-04-10 22:05 UTC (permalink / raw) To: Krzysztof Helt Cc: Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Stefan Richter On Fri, Apr 10, 2009 at 10:21:22PM +0200, Krzysztof Helt wrote: > On Thu, 9 Apr 2009 14:58:51 +0200 > Andrea Righi <righi.andrea@gmail.com> wrote: > > > On Thu, Apr 09, 2009 at 07:36:24PM +0800, Eric Miao wrote: > > > This happens on my Marvell PXA310-based Littleton platform with > > > Angstrom Distribution. The offending paths are many: > > > > > > FBIOPUT_VSCREENINFO: > > > lock_fb_info() > > > --> fb_set_var() > > > --> fb_notifier_call_chain() [FBINFO_MISC_USEREVENT] > > > --> fbcon_event_notifier() [FB_EVENT_MODE_CHANGE] > > > --> lock_fb_info() > > > > > > OK, now hang. I'd suggest a clean fix to the original assumption of > > > circular locking > > > issue and revert this commit first. > > > > > > -- > > > Cheers > > > - eric > > > > I can agree to revert 66c1ca019078220dc1bf968f2bb18421100ef147, since I > > don't have a clean fix for this. Pushing down fb_info->lock in > > fb_set_var() excluding to call fb_notifier_call_chain with fb_info->lock > > held doesn't seem to be so trivial... > > > > However, reverting this will re-introduce the circular locking > > dependency fb_info->lock => mm->mmap_sem => fb_info->lock. > > > > If anybody is interested I have looked into the code of the fb_mmap() > and have found that the problem Andrea tried to fix is caused > only by drivers which implements their own fb_mmap(). Krzysztof, first of all thanks for looking into the code! > > The correct solution is to push the info->lock mutex into > the fb_mmap() implemented inside the drivers. Some drivers > may not need it (the ones which only calculate offsets > and do not "real" iommaping). mmmh... I may have missed something, but the common fb_mmap() should acquire mm->mmap_sem and then info->lock, while fb_ioctl() can do that in reverse order (info->lock first and then mm->mmap_sem) causing the circular locking dependency. Are you sure that pushing info->lock down each driver's fb_mmap will fix the problem? > > I'll try to prepare a patch after the Easters. This will require a revert > of the 66c1ca commit. Thanks and happy Easter, -Andrea > > Happy Easters, > Krzysztof > > ---------------------------------------------------------------------- > Nagrody w jednym miejscu! > Sprawdz >> http://link.interia.pl/f210b > ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-10 22:05 ` Andrea Righi @ 2009-04-11 6:04 ` Krzysztof Helt [not found] ` <49E05C36.9040204@s5r6.in-berlin.de> 0 siblings, 1 reply; 11+ messages in thread From: Krzysztof Helt @ 2009-04-11 6:04 UTC (permalink / raw) To: Andrea Righi Cc: Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Stefan Richter On Sat, 11 Apr 2009 00:05:22 +0200 Andrea Righi <righi.andrea@gmail.com> wrote: > > mmmh... I may have missed something, but the common fb_mmap() should > acquire mm->mmap_sem and then info->lock, while fb_ioctl() can do that > in reverse order (info->lock first and then mm->mmap_sem) causing the > circular locking dependency. Are you sure that pushing info->lock down > each driver's fb_mmap will fix the problem? Right. The fb_mmap is called with the mmap_sem already held. I will try other possibilities like breaking info->lock() into two mutexex. Something should be done to solve this problem. Best regards, Krzysztof ---------------------------------------------------------------------- Oblej swoich znajomych... wirtualnie! ;) http://link.interia.pl/f2119 ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <49E05C36.9040204@s5r6.in-berlin.de>]
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working [not found] ` <49E05C36.9040204@s5r6.in-berlin.de> @ 2009-04-11 11:08 ` Andrea Righi 2009-04-11 15:04 ` Andrea Righi [not found] ` <20090411150359.GA8265@linux> 0 siblings, 2 replies; 11+ messages in thread From: Andrea Righi @ 2009-04-11 11:08 UTC (permalink / raw) To: Stefan Richter Cc: Krzysztof Helt, Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner On Sat, Apr 11, 2009 at 11:00:38AM +0200, Stefan Richter wrote: > Krzysztof Helt wrote: > > On Sat, 11 Apr 2009 00:05:22 +0200 > > Andrea Righi <righi.andrea@gmail.com> wrote: > > > >> mmmh... I may have missed something, but the common fb_mmap() should > >> acquire mm->mmap_sem and then info->lock, while fb_ioctl() can do that > >> in reverse order (info->lock first and then mm->mmap_sem) causing the > >> circular locking dependency. Are you sure that pushing info->lock down > >> each driver's fb_mmap will fix the problem? > > > > Right. The fb_mmap is called with the mmap_sem already held. > > I will try other possibilities like breaking info->lock() into two > > mutexex. > > I had to deal with interaction of mmap_sem with a driver lock twice yet. > I solved it cheaply by replacing mutex_lock(driver_mutex) by > mutex_trylock(driver_mutex). > > The obvious drawback is that thic changes kernel behaviour visibly to > userspace: Under contention, the ioctl/read/write fails with -EAGAIN > instead of being blocked until the other thread finished its > ioctl/read/write/mmap on the same fd (if the driver mutex is > instantiated per fd, like in my case). > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8449fc3ae58bf8ee5acbd2280754cde67b5db128 > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=638570b54346f140bc09b986d93e76025d35180f > > (In these two drivers, the change of behaviour is irrelevant to real > userspace clients.) I've looked at the code again. I think the main problem here (at last the last one reported) is that 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. Probably we can just remove the lock/unlock_fb_info() in all the fb notifier callbacks' and be sure to always call fb_notifier_call_chain() with info->lock held. Something like this (untested). I'll test it later and re-submit if it makes sense. Signed-off-by: Andrea Righi <righi.andrea@gmail.com> --- drivers/video/backlight/backlight.c | 3 -- drivers/video/backlight/lcd.c | 3 -- drivers/video/console/fbcon.c | 55 ++--------------------------------- drivers/video/fbmem.c | 19 ++++++++++++ 4 files changed, 22 insertions(+), 58 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index dd37cbc..157057c 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -35,8 +35,6 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); - if (!lock_fb_info(evdata->info)) - return -ENODEV; mutex_lock(&bd->ops_lock); if (bd->ops) if (!bd->ops->check_fb || @@ -49,7 +47,6 @@ static int fb_notifier_callback(struct notifier_block *self, backlight_update_status(bd); } mutex_unlock(&bd->ops_lock); - unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 0bb13df..b644947 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -40,8 +40,6 @@ static int fb_notifier_callback(struct notifier_block *self, if (!ld->ops) return 0; - if (!lock_fb_info(evdata->info)) - return -ENODEV; mutex_lock(&ld->ops_lock); if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { if (event == FB_EVENT_BLANK) { @@ -53,7 +51,6 @@ static int fb_notifier_callback(struct notifier_block *self, } } mutex_unlock(&ld->ops_lock); - unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 2cd500a..ec7d9ba 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2263,9 +2263,12 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, } + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; event.data = ␣ fb_notifier_call_chain(FB_EVENT_CONBLANK, &event); + unlock_fb_info(info); } static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) @@ -2956,8 +2959,6 @@ static int fbcon_fb_unregistered(struct fb_info *info) { int i, idx; - if (!lock_fb_info(info)) - return -ENODEV; idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) @@ -2985,8 +2986,6 @@ static int fbcon_fb_unregistered(struct fb_info *info) if (primary_device == idx) primary_device = -1; - unlock_fb_info(info); - if (!num_registered_fb) unregister_con_driver(&fb_con); @@ -3027,11 +3026,8 @@ static int fbcon_fb_registered(struct fb_info *info) { int ret = 0, i, idx; - if (!lock_fb_info(info)) - return -ENODEV; idx = info->node; fbcon_select_primary(info); - unlock_fb_info(info); if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3152,53 +3148,23 @@ static int fbcon_event_notify(struct notifier_block *self, switch(action) { case FB_EVENT_SUSPEND: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_suspended(info); - unlock_fb_info(info); break; case FB_EVENT_RESUME: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_resumed(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_modechanged(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE_ALL: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_set_all_vcs(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_DELETE: mode = event->data; - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } ret = fbcon_mode_deleted(info, mode); - unlock_fb_info(info); break; case FB_EVENT_FB_UNBIND: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } idx = info->node; - unlock_fb_info(info); ret = fbcon_fb_unbind(idx); break; case FB_EVENT_FB_REGISTERED: @@ -3217,29 +3183,14 @@ static int fbcon_event_notify(struct notifier_block *self, con2fb->framebuffer = con2fb_map[con2fb->console - 1]; break; case FB_EVENT_BLANK: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_fb_blanked(info, *(int *)event->data); - unlock_fb_info(info); break; case FB_EVENT_NEW_MODELIST: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_new_modelist(info); - unlock_fb_info(info); break; case FB_EVENT_GET_REQ: caps = event->data; - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_get_requirement(info, caps); - unlock_fb_info(info); break; } done: diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 2ac32e6..d412a1d 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, return -EINVAL; con2fb.framebuffer = -1; event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); + unlock_fb_info(info); ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; break; case FBIOPUT_CON2FBMAP: @@ -1115,8 +1118,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, break; } event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); + unlock_fb_info(info); break; case FBIOBLANK: if (!lock_fb_info(info)) @@ -1521,7 +1527,10 @@ register_framebuffer(struct fb_info *fb_info) registered_fb[i] = fb_info; event.info = fb_info; + if (!lock_fb_info(fb_info)) + return -ENODEV; fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + unlock_fb_info(fb_info); return 0; } @@ -1555,8 +1564,12 @@ unregister_framebuffer(struct fb_info *fb_info) goto done; } + + if (!lock_fb_info(fb_info)) + return -ENODEV; event.info = fb_info; ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + unlock_fb_info(fb_info); if (ret) { ret = -EINVAL; @@ -1590,6 +1603,8 @@ void fb_set_suspend(struct fb_info *info, int state) { struct fb_event event; + if (!lock_fb_info(info)) + return; event.info = info; if (state) { fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); @@ -1598,6 +1613,7 @@ void fb_set_suspend(struct fb_info *info, int state) info->state = FBINFO_STATE_RUNNING; fb_notifier_call_chain(FB_EVENT_RESUME, &event); } + unlock_fb_info(info); } /** @@ -1667,8 +1683,11 @@ int fb_new_modelist(struct fb_info *info) err = 1; if (!list_empty(&info->modelist)) { + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); + unlock_fb_info(info); } return err; ^ permalink raw reply related [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-11 11:08 ` Andrea Righi @ 2009-04-11 15:04 ` Andrea Righi [not found] ` <20090411150359.GA8265@linux> 1 sibling, 0 replies; 11+ messages in thread From: Andrea Righi @ 2009-04-11 15:04 UTC (permalink / raw) To: Stefan Richter, Krzysztof Helt, Eric Miao, LKML, Geert Uytterhoeven <geert@ On Sat, Apr 11, 2009 at 01:08:41PM +0200, Andrea Righi wrote: > On Sat, Apr 11, 2009 at 11:00:38AM +0200, Stefan Richter wrote: > > Krzysztof Helt wrote: > > > On Sat, 11 Apr 2009 00:05:22 +0200 > > > Andrea Righi <righi.andrea@gmail.com> wrote: > > > > > >> mmmh... I may have missed something, but the common fb_mmap() should > > >> acquire mm->mmap_sem and then info->lock, while fb_ioctl() can do that > > >> in reverse order (info->lock first and then mm->mmap_sem) causing the > > >> circular locking dependency. Are you sure that pushing info->lock down > > >> each driver's fb_mmap will fix the problem? > > > > > > Right. The fb_mmap is called with the mmap_sem already held. > > > I will try other possibilities like breaking info->lock() into two > > > mutexex. > > > > I had to deal with interaction of mmap_sem with a driver lock twice yet. > > I solved it cheaply by replacing mutex_lock(driver_mutex) by > > mutex_trylock(driver_mutex). > > > > The obvious drawback is that thic changes kernel behaviour visibly to > > userspace: Under contention, the ioctl/read/write fails with -EAGAIN > > instead of being blocked until the other thread finished its > > ioctl/read/write/mmap on the same fd (if the driver mutex is > > instantiated per fd, like in my case). > > > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=8449fc3ae58bf8ee5acbd2280754cde67b5db128 > > http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=638570b54346f140bc09b986d93e76025d35180f > > > > (In these two drivers, the change of behaviour is irrelevant to real > > userspace clients.) > > I've looked at the code again. I think the main problem here (at last > the last one reported) is that 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. > > Probably we can just remove the lock/unlock_fb_info() in all the fb > notifier callbacks' and be sure to always call fb_notifier_call_chain() > with info->lock held. > > Something like this (untested). I'll test it later and re-submit if it > makes sense. Tested intelfb and X11 with fbdev. It seems to work fine, but I may be unable to test the mode switching right now: intelfb: Non-CRT device is enabled ( LVDS port ). Disabling mode switching. It would be great if someone could help me to test this patch (against latest Linus' git - no need to revert 66c1ca). Thanks, -Andrea --- 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> --- drivers/video/backlight/backlight.c | 3 -- drivers/video/backlight/lcd.c | 3 -- drivers/video/console/fbcon.c | 55 ++--------------------------------- drivers/video/fbmem.c | 19 ++++++++++++ 4 files changed, 22 insertions(+), 58 deletions(-) diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c index dd37cbc..157057c 100644 --- a/drivers/video/backlight/backlight.c +++ b/drivers/video/backlight/backlight.c @@ -35,8 +35,6 @@ static int fb_notifier_callback(struct notifier_block *self, return 0; bd = container_of(self, struct backlight_device, fb_notif); - if (!lock_fb_info(evdata->info)) - return -ENODEV; mutex_lock(&bd->ops_lock); if (bd->ops) if (!bd->ops->check_fb || @@ -49,7 +47,6 @@ static int fb_notifier_callback(struct notifier_block *self, backlight_update_status(bd); } mutex_unlock(&bd->ops_lock); - unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index 0bb13df..b644947 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c @@ -40,8 +40,6 @@ static int fb_notifier_callback(struct notifier_block *self, if (!ld->ops) return 0; - if (!lock_fb_info(evdata->info)) - return -ENODEV; mutex_lock(&ld->ops_lock); if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { if (event == FB_EVENT_BLANK) { @@ -53,7 +51,6 @@ static int fb_notifier_callback(struct notifier_block *self, } } mutex_unlock(&ld->ops_lock); - unlock_fb_info(evdata->info); return 0; } diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c index 2cd500a..471a9a6 100644 --- a/drivers/video/console/fbcon.c +++ b/drivers/video/console/fbcon.c @@ -2263,9 +2263,12 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info, } + if (!lock_fb_info(info)) + return; event.info = info; event.data = ␣ fb_notifier_call_chain(FB_EVENT_CONBLANK, &event); + unlock_fb_info(info); } static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch) @@ -2956,8 +2959,6 @@ static int fbcon_fb_unregistered(struct fb_info *info) { int i, idx; - if (!lock_fb_info(info)) - return -ENODEV; idx = info->node; for (i = first_fb_vc; i <= last_fb_vc; i++) { if (con2fb_map[i] == idx) @@ -2985,8 +2986,6 @@ static int fbcon_fb_unregistered(struct fb_info *info) if (primary_device == idx) primary_device = -1; - unlock_fb_info(info); - if (!num_registered_fb) unregister_con_driver(&fb_con); @@ -3027,11 +3026,8 @@ static int fbcon_fb_registered(struct fb_info *info) { int ret = 0, i, idx; - if (!lock_fb_info(info)) - return -ENODEV; idx = info->node; fbcon_select_primary(info); - unlock_fb_info(info); if (info_idx == -1) { for (i = first_fb_vc; i <= last_fb_vc; i++) { @@ -3152,53 +3148,23 @@ static int fbcon_event_notify(struct notifier_block *self, switch(action) { case FB_EVENT_SUSPEND: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_suspended(info); - unlock_fb_info(info); break; case FB_EVENT_RESUME: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_resumed(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_modechanged(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_CHANGE_ALL: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_set_all_vcs(info); - unlock_fb_info(info); break; case FB_EVENT_MODE_DELETE: mode = event->data; - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } ret = fbcon_mode_deleted(info, mode); - unlock_fb_info(info); break; case FB_EVENT_FB_UNBIND: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } idx = info->node; - unlock_fb_info(info); ret = fbcon_fb_unbind(idx); break; case FB_EVENT_FB_REGISTERED: @@ -3217,29 +3183,14 @@ static int fbcon_event_notify(struct notifier_block *self, con2fb->framebuffer = con2fb_map[con2fb->console - 1]; break; case FB_EVENT_BLANK: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_fb_blanked(info, *(int *)event->data); - unlock_fb_info(info); break; case FB_EVENT_NEW_MODELIST: - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_new_modelist(info); - unlock_fb_info(info); break; case FB_EVENT_GET_REQ: caps = event->data; - if (!lock_fb_info(info)) { - ret = -ENODEV; - goto done; - } fbcon_get_requirement(info, caps); - unlock_fb_info(info); break; } done: diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 2ac32e6..d412a1d 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, return -EINVAL; con2fb.framebuffer = -1; event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event); + unlock_fb_info(info); ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0; break; case FBIOPUT_CON2FBMAP: @@ -1115,8 +1118,11 @@ static long do_fb_ioctl(struct fb_info *info, unsigned int cmd, break; } event.data = &con2fb; + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event); + unlock_fb_info(info); break; case FBIOBLANK: if (!lock_fb_info(info)) @@ -1521,7 +1527,10 @@ register_framebuffer(struct fb_info *fb_info) registered_fb[i] = fb_info; event.info = fb_info; + if (!lock_fb_info(fb_info)) + return -ENODEV; fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event); + unlock_fb_info(fb_info); return 0; } @@ -1555,8 +1564,12 @@ unregister_framebuffer(struct fb_info *fb_info) goto done; } + + if (!lock_fb_info(fb_info)) + return -ENODEV; event.info = fb_info; ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event); + unlock_fb_info(fb_info); if (ret) { ret = -EINVAL; @@ -1590,6 +1603,8 @@ void fb_set_suspend(struct fb_info *info, int state) { struct fb_event event; + if (!lock_fb_info(info)) + return; event.info = info; if (state) { fb_notifier_call_chain(FB_EVENT_SUSPEND, &event); @@ -1598,6 +1613,7 @@ void fb_set_suspend(struct fb_info *info, int state) info->state = FBINFO_STATE_RUNNING; fb_notifier_call_chain(FB_EVENT_RESUME, &event); } + unlock_fb_info(info); } /** @@ -1667,8 +1683,11 @@ int fb_new_modelist(struct fb_info *info) err = 1; if (!list_empty(&info->modelist)) { + if (!lock_fb_info(info)) + return -ENODEV; event.info = info; err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event); + unlock_fb_info(info); } return err; ------------------------------------------------------------------------------ This SF.net email is sponsored by: High Quality Requirements in a Collaborative Environment. Download a free trial of Rational Requirements Composer Now! http://p.sf.net/sfu/www-ibm-com ^ permalink raw reply related [flat|nested] 11+ messages in thread
[parent not found: <20090411150359.GA8265@linux>]
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working [not found] ` <20090411150359.GA8265@linux> @ 2009-04-11 18:21 ` Andrew Morton 2009-04-11 19:32 ` Andrea Righi 2009-04-13 23:34 ` Andreas Schwab [not found] ` <20090417182507.0bd85ccc.krzysztof.h1@poczta.fm> 2 siblings, 1 reply; 11+ messages in thread From: Andrew Morton @ 2009-04-11 18:21 UTC (permalink / raw) To: Andrea Righi Cc: Pavel Roskin, Antonino A. Daplas, Andrey Borzenkov, Harvey, Johannes Weiner, Krzysztof Helt, LKML, Stefan Richter, Geert Uytterhoeven, linux-fbdev-devel, linux-pm, Harrison On Sat, 11 Apr 2009 17:04:00 +0200 Andrea Righi <righi.andrea@gmail.com> wrote: > 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. Thanks. So do you think we should proceed with this patch instead of reverting 66c1ca0? ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working 2009-04-11 18:21 ` Andrew Morton @ 2009-04-11 19:32 ` Andrea Righi 0 siblings, 0 replies; 11+ messages in thread From: Andrea Righi @ 2009-04-11 19:32 UTC (permalink / raw) To: Andrew Morton Cc: Stefan Richter, Krzysztof Helt, Eric Miao, LKML, Geert Uytterhoeven, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Pavel Roskin On Sat, Apr 11, 2009 at 11:21:31AM -0700, Andrew Morton wrote: > On Sat, 11 Apr 2009 17:04:00 +0200 Andrea Righi <righi.andrea@gmail.com> wrote: > > > 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. > > Thanks. So do you think we should proceed with this patch instead of > reverting 66c1ca0? Yes, there's no need to revert 66c1ca0 now, otherwise we'll simply reintroduce the info->lock / mm->mmap_sem circular locking dependency. I'd like to test the fbdev mode switching, but it seems intelfb doesn't support it with LVDS ports (and at the moment I've not a CRT here...). Anyway, if someone will have troubles with mode switching I'm quite sure we can fix it on top of this patch. -Andrea ^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working [not found] ` <20090411150359.GA8265@linux> 2009-04-11 18:21 ` Andrew Morton @ 2009-04-13 23:34 ` Andreas Schwab [not found] ` <20090417182507.0bd85ccc.krzysztof.h1@poczta.fm> 2 siblings, 0 replies; 11+ messages in thread From: Andreas Schwab @ 2009-04-13 23:34 UTC (permalink / raw) To: Stefan Richter Cc: Krzysztof Helt, Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Pavel Roskin Andrea Righi <righi.andrea@gmail.com> writes: > Tested intelfb and X11 with fbdev. It seems to work fine, but I may be > unable to test the mode switching right now: > > intelfb: Non-CRT device is enabled ( LVDS port ). Disabling mode switching. > > It would be great if someone could help me to test this patch (against > latest Linus' git - no need to revert 66c1ca). I can confirm that it fixes the issue. Tested with radeonfb and MOL. Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 11+ messages in thread
[parent not found: <20090417182507.0bd85ccc.krzysztof.h1@poczta.fm>]
* Re: [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working [not found] ` <20090417182507.0bd85ccc.krzysztof.h1@poczta.fm> @ 2009-04-17 22:51 ` Andrea Righi 0 siblings, 0 replies; 11+ messages in thread From: Andrea Righi @ 2009-04-17 22:51 UTC (permalink / raw) To: Krzysztof Helt Cc: Stefan Richter, Eric Miao, LKML, Geert Uytterhoeven, Andrew Morton, Rafael J. Wysocki, Andrey Borzenkov, Antonino A. Daplas, linux-fbdev-devel, linux-pm, Dave Jones, Harvey Harrison, Johannes Weiner, Pavel Roskin On Fri, Apr 17, 2009 at 06:25:07PM +0200, Krzysztof Helt wrote: > On Sat, 11 Apr 2009 17:04:00 +0200 > Andrea Righi <righi.andrea@gmail.com> wrote: > > > It would be great if someone could help me to test this patch (against > > latest Linus' git - no need to revert 66c1ca). > > > > I can confirm the patch fixes the issue on radeonfb and cirrusfb drivers tested so far. > > Regards, > Krzysztof Thanks for testing! -Andrea ^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2009-04-17 22:51 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <f17812d70904090436kd03744brca4a4bc4b85bba8@mail.gmail.com>
2009-04-09 12:58 ` [REGRESSION] commit 66c1ca0: {fbmem: fix fb_info->lock and mm->mmap_sem ...} causes Xfbdev not working Andrea Righi
2009-04-10 20:21 ` Krzysztof Helt
2009-04-10 21:16 ` Andrew Morton
2009-04-10 22:05 ` Andrea Righi
2009-04-11 6:04 ` Krzysztof Helt
[not found] ` <49E05C36.9040204@s5r6.in-berlin.de>
2009-04-11 11:08 ` Andrea Righi
2009-04-11 15:04 ` Andrea Righi
[not found] ` <20090411150359.GA8265@linux>
2009-04-11 18:21 ` Andrew Morton
2009-04-11 19:32 ` Andrea Righi
2009-04-13 23:34 ` Andreas Schwab
[not found] ` <20090417182507.0bd85ccc.krzysztof.h1@poczta.fm>
2009-04-17 22:51 ` Andrea Righi
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).