From: Herbert Xu The following patch adds basic module reference counting to vt console drivers. Currently modules like fbcon are not counted at all. --- 25-akpm/drivers/char/vt.c | 29 ++++++++++++++++++++++++---- 25-akpm/drivers/video/console/dummycon.c | 2 + 25-akpm/drivers/video/console/fbcon.c | 12 ++++++++--- 25-akpm/drivers/video/console/mdacon.c | 8 +------ 25-akpm/drivers/video/console/newport_con.c | 5 +--- 25-akpm/drivers/video/console/promcon.c | 1 25-akpm/drivers/video/console/sticon.c | 3 +- 25-akpm/drivers/video/console/vgacon.c | 1 25-akpm/include/linux/console.h | 4 ++- 9 files changed, 47 insertions(+), 18 deletions(-) diff -puN drivers/char/vt.c~module-ref-counting-for-vt-console-drivers drivers/char/vt.c --- 25/drivers/char/vt.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/char/vt.c Thu Apr 29 15:51:32 2004 @@ -661,11 +661,14 @@ int vc_cons_allocated(unsigned int i) static void visual_init(int currcons, int init) { /* ++Geert: sw->con_init determines console size */ + if (sw) + module_put(sw->owner); sw = conswitchp; #ifndef VT_SINGLE_DRIVER if (con_driver_map[currcons]) sw = con_driver_map[currcons]; #endif + __module_get(sw->owner); cons_num = currcons; display_fg = &master_display_fg; vc_cons[currcons].d->vc_uni_pagedir_loc = &vc_cons[currcons].d->vc_uni_pagedir; @@ -2668,25 +2671,38 @@ static void clear_buffer_attributes(int * and become default driver for newly opened ones. */ -void take_over_console(const struct consw *csw, int first, int last, int deflt) +int take_over_console(const struct consw *csw, int first, int last, int deflt) { int i, j = -1; const char *desc; + struct module *owner; + + owner = csw->owner; + if (!try_module_get(owner)) + return -ENODEV; acquire_console_sem(); desc = csw->con_startup(); if (!desc) { release_console_sem(); - return; + module_put(owner); + return -ENODEV; } - if (deflt) + if (deflt) { + if (conswitchp) + module_put(conswitchp->owner); + __module_get(owner); conswitchp = csw; + } for (i = first; i <= last; i++) { int old_was_color; int currcons = i; + if (con_driver_map[i]) + module_put(con_driver_map[i]->owner); + __module_get(owner); con_driver_map[i] = csw; if (!vc_cons[i].d || !vc_cons[i].d->vc_sw) @@ -2721,6 +2737,9 @@ void take_over_console(const struct cons printk("to %s\n", desc); release_console_sem(); + + module_put(owner); + return 0; } void give_up_console(const struct consw *csw) @@ -2728,8 +2747,10 @@ void give_up_console(const struct consw int i; for(i = 0; i < MAX_NR_CONSOLES; i++) - if (con_driver_map[i] == csw) + if (con_driver_map[i] == csw) { + module_put(csw->owner); con_driver_map[i] = NULL; + } } #endif diff -puN drivers/video/console/dummycon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/dummycon.c --- 25/drivers/video/console/dummycon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/dummycon.c Thu Apr 29 15:51:32 2004 @@ -11,6 +11,7 @@ #include #include #include +#include /* * Dummy console driver @@ -58,6 +59,7 @@ static int dummycon_dummy(void) */ const struct consw dummy_con = { + .owner = THIS_MODULE, .con_startup = dummycon_startup, .con_init = dummycon_init, .con_deinit = DUMMY, diff -puN drivers/video/console/fbcon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/fbcon.c --- 25/drivers/video/console/fbcon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/fbcon.c Thu Apr 29 15:51:32 2004 @@ -304,8 +304,7 @@ int set_con2fb_map(int unit, int newidx) return -ENODEV; con2fb_map[unit] = newidx; fbcon_is_default = (vc->vc_sw == &fb_con) ? 1 : 0; - take_over_console(&fb_con, unit, unit, fbcon_is_default); - return 0; + return take_over_console(&fb_con, unit, unit, fbcon_is_default); } /* @@ -2240,6 +2239,7 @@ static int fbcon_event_notify(struct not */ const struct consw fb_con = { + .owner = THIS_MODULE, .con_startup = fbcon_startup, .con_init = fbcon_init, .con_deinit = fbcon_deinit, @@ -2269,10 +2269,16 @@ static int fbcon_event_notifier_register int __init fb_console_init(void) { + int err; + if (!num_registered_fb) return -ENODEV; - take_over_console(&fb_con, first_fb_vc, last_fb_vc, fbcon_is_default); + err = take_over_console(&fb_con, first_fb_vc, last_fb_vc, + fbcon_is_default); + if (err) + return err; + acquire_console_sem(); if (!fbcon_event_notifier_registered) { fb_register_client(&fbcon_event_notifer); diff -puN drivers/video/console/mdacon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/mdacon.c --- 25/drivers/video/console/mdacon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/mdacon.c Thu Apr 29 15:51:32 2004 @@ -370,8 +370,6 @@ static void mdacon_init(struct vc_data * if (mda_display_fg == NULL) mda_display_fg = c; - - MOD_INC_USE_COUNT; } static void mdacon_deinit(struct vc_data *c) @@ -380,8 +378,6 @@ static void mdacon_deinit(struct vc_data if (mda_display_fg == c) mda_display_fg = NULL; - - MOD_DEC_USE_COUNT; } static inline u16 mda_convert_attr(u16 ch) @@ -586,6 +582,7 @@ static int mdacon_scroll(struct vc_data */ const struct consw mda_con = { + .owner = THIS_MODULE, .con_startup = mdacon_startup, .con_init = mdacon_init, .con_deinit = mdacon_deinit, @@ -609,8 +606,7 @@ int __init mda_console_init(void) if (mda_first_vc > mda_last_vc) return 1; - take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); - return 0; + return take_over_console(&mda_con, mda_first_vc-1, mda_last_vc-1, 0); } void __exit mda_console_exit(void) diff -puN drivers/video/console/newport_con.c~module-ref-counting-for-vt-console-drivers drivers/video/console/newport_con.c --- 25/drivers/video/console/newport_con.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/newport_con.c Thu Apr 29 15:53:24 2004 @@ -705,6 +705,7 @@ static int newport_dummy(struct vc_data #define DUMMY (void *) newport_dummy const struct consw newport_con = { + .owner = THIS_MODULE, .con_startup = newport_startup, .con_init = newport_init, .con_deinit = newport_deinit, @@ -726,9 +727,7 @@ const struct consw newport_con = { #ifdef MODULE static int __init newport_console_init(void) { - take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); - - return 0; + return take_over_console(&newport_con, 0, MAX_NR_CONSOLES - 1, 1); } static void __exit newport_console_exit(void) diff -puN drivers/video/console/promcon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/promcon.c --- 25/drivers/video/console/promcon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/promcon.c Thu Apr 29 15:51:32 2004 @@ -574,6 +574,7 @@ static int promcon_dummy(void) #define DUMMY (void *) promcon_dummy const struct consw prom_con = { + .owner = THIS_MODULE, .con_startup = promcon_startup, .con_init = promcon_init, .con_deinit = promcon_deinit, diff -puN drivers/video/console/sticon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/sticon.c --- 25/drivers/video/console/sticon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/sticon.c Thu Apr 29 15:51:32 2004 @@ -354,6 +354,7 @@ static void sticon_save_screen(struct vc } static struct consw sti_con = { + .owner = THIS_MODULE, .con_startup = sticon_startup, .con_init = sticon_init, .con_deinit = sticon_deinit, @@ -390,7 +391,7 @@ int __init sticonsole_init(void) if (conswitchp == &dummy_con) { printk(KERN_INFO "sticon: Initializing STI text console.\n"); - take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1); + return take_over_console(&sti_con, 0, MAX_NR_CONSOLES - 1, 1); } return 0; } diff -puN drivers/video/console/vgacon.c~module-ref-counting-for-vt-console-drivers drivers/video/console/vgacon.c --- 25/drivers/video/console/vgacon.c~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/drivers/video/console/vgacon.c Thu Apr 29 15:51:32 2004 @@ -1065,6 +1065,7 @@ static int vgacon_dummy(struct vc_data * #define DUMMY (void *) vgacon_dummy const struct consw vga_con = { + .owner = THIS_MODULE, .con_startup = vgacon_startup, .con_init = vgacon_init, .con_deinit = vgacon_deinit, diff -puN include/linux/console.h~module-ref-counting-for-vt-console-drivers include/linux/console.h --- 25/include/linux/console.h~module-ref-counting-for-vt-console-drivers Thu Apr 29 15:51:32 2004 +++ 25-akpm/include/linux/console.h Thu Apr 29 15:51:32 2004 @@ -19,6 +19,7 @@ struct vc_data; struct console_font_op; +struct module; /* * this is what the terminal answers to a ESC-Z or csi0c query. @@ -27,6 +28,7 @@ struct console_font_op; #define VT102ID "\033[?6c" struct consw { + struct module *owner; const char *(*con_startup)(void); void (*con_init)(struct vc_data *, int); void (*con_deinit)(struct vc_data *); @@ -58,7 +60,7 @@ extern const struct consw vga_con; /* VG extern const struct consw newport_con; /* SGI Newport console */ extern const struct consw prom_con; /* SPARC PROM console */ -void take_over_console(const struct consw *sw, int first, int last, int deflt); +int take_over_console(const struct consw *sw, int first, int last, int deflt); void give_up_console(const struct consw *sw); /* scroll */ _