Commit 1c8ce271 authored by Antonino A. Daplas's avatar Antonino A. Daplas Committed by Linus Torvalds

[PATCH] Detaching fbcon: fix give_up_console()

To allow for detaching fbcon, it must be able to give up the console.
However, the function give_up_console() is plain broken.  It just sets the
entries in the console driver map to NULL, it leaves the vt layer without a
console driver, and does not decrement the module reference count.  Calling
give_up_console() is guaranteed to hang the machine..

To fix this problem, ensure that the virtual consoles are not left dangling
without a driver.  All systems have a default boot driver (either vgacon or
dummycon) which is never unloaded.  For those vt's that lost their driver, the
default boot driver is reassigned back to them.
Signed-off-by: default avatarAntonino Daplas <adaplas@pol.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 50ec42ed
...@@ -100,6 +100,7 @@ ...@@ -100,6 +100,7 @@
const struct consw *conswitchp; const struct consw *conswitchp;
static struct consw *defcsw; /* default console */
/* A bitmap for codes <32. A bit of 1 indicates that the code /* A bitmap for codes <32. A bit of 1 indicates that the code
* corresponding to that bit number invokes some special action * corresponding to that bit number invokes some special action
...@@ -2673,17 +2674,23 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) ...@@ -2673,17 +2674,23 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
if (!try_module_get(owner)) if (!try_module_get(owner))
return -ENODEV; return -ENODEV;
acquire_console_sem(); /* save default console, for possible recovery later on */
if (!defcsw)
defcsw = (struct consw *) conswitchp;
acquire_console_sem();
desc = csw->con_startup(); desc = csw->con_startup();
if (!desc) { if (!desc) {
release_console_sem(); release_console_sem();
module_put(owner); module_put(owner);
return -ENODEV; return -ENODEV;
} }
if (deflt) { if (deflt) {
if (conswitchp) if (conswitchp)
module_put(conswitchp->owner); module_put(conswitchp->owner);
__module_get(owner); __module_get(owner);
conswitchp = csw; conswitchp = csw;
} }
...@@ -2701,6 +2708,7 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) ...@@ -2701,6 +2708,7 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
continue; continue;
j = i; j = i;
if (CON_IS_VISIBLE(vc)) { if (CON_IS_VISIBLE(vc)) {
k = i; k = i;
save_screen(vc); save_screen(vc);
...@@ -2709,10 +2717,8 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) ...@@ -2709,10 +2717,8 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
old_was_color = vc->vc_can_do_color; old_was_color = vc->vc_can_do_color;
vc->vc_sw->con_deinit(vc); vc->vc_sw->con_deinit(vc);
vc->vc_origin = (unsigned long)vc->vc_screenbuf; vc->vc_origin = (unsigned long)vc->vc_screenbuf;
vc->vc_visible_origin = vc->vc_origin;
vc->vc_scr_end = vc->vc_origin + vc->vc_screenbuf_size;
vc->vc_pos = vc->vc_origin + vc->vc_size_row * vc->vc_y + 2 * vc->vc_x;
visual_init(vc, i, 0); visual_init(vc, i, 0);
set_origin(vc);
update_attr(vc); update_attr(vc);
/* If the console changed between mono <-> color, then /* If the console changed between mono <-> color, then
...@@ -2741,22 +2747,29 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt) ...@@ -2741,22 +2747,29 @@ int take_over_console(const struct consw *csw, int first, int last, int deflt)
printk("to %s\n", desc); printk("to %s\n", desc);
release_console_sem(); release_console_sem();
module_put(owner); module_put(owner);
return 0; return 0;
} }
void give_up_console(const struct consw *csw) void give_up_console(const struct consw *csw)
{ {
int i; int i, first = -1, last = -1, deflt = 0;
for(i = 0; i < MAX_NR_CONSOLES; i++) for (i = 0; i < MAX_NR_CONSOLES; i++)
if (con_driver_map[i] == csw) { if (con_driver_map[i] == csw) {
if (first == -1)
first = i;
last = i;
module_put(csw->owner); module_put(csw->owner);
con_driver_map[i] = NULL; con_driver_map[i] = NULL;
} }
}
if (first != -1 && defcsw) {
if (first == 0 && last == MAX_NR_CONSOLES - 1)
deflt = 1;
take_over_console(defcsw, first, last, deflt);
}
}
#endif #endif
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment