mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 15:29:16 +00:00
ps3fb: fix deadlock on kexec()
Since the introduction of the acquire_console_sem calls in 0333d83509c7d8496c8965b5ba9bc0c98e83c259, kexecing can cause the kernel to deadlock: ps3fb_shutdown() -> unregister_framebuffer() -> fb_notifier_call_chain(FB_EVENT_FB_UNBIND) -> fbcon_fb_unbind() -> unbind_con_driver() -> bind_con_driver() [ acquires console_sem ] -> fbcon_deinit() -> fbops->fb_release(newinfo, 0) -> ps3fb_release() -> ps3fb_sync() [ acquires console_sem ] This change avoids the deadlock by moving the acquire_console_sem() out of ps3fb_sync(), and puts it into the two other callsites, leaving ps3fb_release() to call ps3fb_sync() without the console semaphore. [Geert] - Corrected call sequence above - ps3fb_release() may be called with and without console_sem held. This is an inconsistency that should be fixed at the fb level, but for now, try to acquire console_sem in ps3fb_release(). I think it's safer to let ps3fb_release() try to acquire console_sem and not refresh the screen if it fails, than to call ps3fb_sync() without holding console_sem, as ps3fb_par may be modified at the same time, causing crashes or lockups. Besides, ps3fb_release() only calls ps3fb_sync() to refresh the screen when display flipping is disabled, which is an uncommon case (except during shutdown/kexec). Signed-off-by: Jeremy Kerr <jk@ozlabs.org> Signed-off-by: Geert Uytterhoeven <Geert.Uytterhoeven@sonycom.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
ba21611c9c
commit
8dab637612
@ -443,8 +443,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
|
||||
u32 ddr_line_length, xdr_line_length;
|
||||
u64 ddr_base, xdr_base;
|
||||
|
||||
acquire_console_sem();
|
||||
|
||||
if (frame > par->num_frames - 1) {
|
||||
dev_dbg(info->device, "%s: invalid frame number (%u)\n",
|
||||
__func__, frame);
|
||||
@ -464,7 +462,6 @@ static int ps3fb_sync(struct fb_info *info, u32 frame)
|
||||
xdr_line_length);
|
||||
|
||||
out:
|
||||
release_console_sem();
|
||||
return error;
|
||||
}
|
||||
|
||||
@ -479,7 +476,10 @@ static int ps3fb_release(struct fb_info *info, int user)
|
||||
if (atomic_dec_and_test(&ps3fb.f_count)) {
|
||||
if (atomic_read(&ps3fb.ext_flip)) {
|
||||
atomic_set(&ps3fb.ext_flip, 0);
|
||||
ps3fb_sync(info, 0); /* single buffer */
|
||||
if (!try_acquire_console_sem()) {
|
||||
ps3fb_sync(info, 0); /* single buffer */
|
||||
release_console_sem();
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -865,7 +865,9 @@ static int ps3fb_ioctl(struct fb_info *info, unsigned int cmd,
|
||||
break;
|
||||
|
||||
dev_dbg(info->device, "PS3FB_IOCTL_FSEL:%d\n", val);
|
||||
acquire_console_sem();
|
||||
retval = ps3fb_sync(info, val);
|
||||
release_console_sem();
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -885,7 +887,9 @@ static int ps3fbd(void *arg)
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (ps3fb.is_kicked) {
|
||||
ps3fb.is_kicked = 0;
|
||||
acquire_console_sem();
|
||||
ps3fb_sync(info, 0); /* single buffer */
|
||||
release_console_sem();
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user