From: Herbert Xu <herbert@gondor.apana.org.au>

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 <linux/console.h>
 #include <linux/vt_kern.h>
 #include <linux/init.h>
+#include <linux/module.h>
 
 /*
  *  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 */

_