[PATCH] Fix for missing release() function

Pavel Roskin proski at gnu.org
Wed Mar 17 14:25:37 GMT 2004


Hello!

I've got this in the kernel log while unloading i82365:

Device 'i823650' does not have a release() function, it is broken and must
be fixed.
Badness in device_release at drivers/base/core.c:85
Call Trace:
 [<c01aa12c>] kobject_cleanup+0x8c/0x90
 [<f89e42a1>] exit_i82365+0x31/0xbe [i82365]
 [<c012a76f>] sys_delete_module+0x11f/0x170
 [<c013d10e>] unmap_vma_list+0xe/0x20
 [<c013d48a>] do_munmap+0xea/0x120
 [<c013d500>] sys_munmap+0x40/0x70
 [<c0106fcb>] syscall_call+0x7/0xb

It looks like that all drivers that use device_register() or
platform_device_register() should supply devices with .release defined.

I checked the kernel drivers, and in most cases those functions are either
empty or call complete().  The idea of the patch is based on floppy.c.

The patch fixes "badness" on unloading i82365.

-- 
Regards,
Pavel Roskin
-------------- next part --------------
--- linux.orig/drivers/pcmcia/hd64465_ss.c
+++ linux/drivers/pcmcia/hd64465_ss.c
@@ -117,6 +117,7 @@ static hs_socket_t hs_sockets[HS_MAX_SOC
 #define IER_ON	    0x3f    	/* interrupts on */
 #define IER_OFF     0x00    	/* interrupts off */
 
+static struct completion device_release;
 /*============================================================*/
 
 #if HD64465_DEBUG > 10
@@ -886,9 +887,17 @@ static struct device_driver hd64465_driv
 	.resume = hd64465_resume,
 };
 
+static void hd64465_device_release(struct device *dev)
+{
+	complete(&device_release);
+}
+
 static struct platform_device hd64465_device = {
 	.name = "hd64465-pcmcia",
 	.id = 0,
+	.dev = {
+		.release = hd64465_device_release,
+	}
 };
 
 static int __init init_hs(void)
@@ -969,6 +978,7 @@ static void __exit exit_hs(void)
 {
 	int i;
 
+	init_completion(&device_release);
 	for (i=0 ; i<HS_MAX_SOCKETS ; i++) {
 		pcmcia_unregister_socket(&hs_sockets[i].socket);
 		hs_exit_socket(&hs_sockets[i]);
@@ -976,6 +986,7 @@ static void __exit exit_hs(void)
 
 	platform_device_unregister(&hd64465_device);
 	unregister_driver(&hd64465_driver);
+	wait_for_completion(&device_release);
 }
 
 module_init(init_hs);
--- linux.orig/drivers/pcmcia/i82365.c
+++ linux/drivers/pcmcia/i82365.c
@@ -191,6 +191,7 @@ static spinlock_t isa_lock = SPIN_LOCK_U
 #define ISA_UNLOCK(n, f) spin_unlock_irqrestore(&isa_lock, f)
 
 static struct timer_list poll_timer;
+static struct completion device_release;
 
 /*====================================================================*/
 
@@ -1362,9 +1363,17 @@ static struct device_driver i82365_drive
 	.resume = i82365_resume,
 };
 
+static void i82365_device_release(struct device *dev)
+{
+	complete(&device_release);
+}
+
 static struct platform_device i82365_device = {
 	.name = "i82365",
 	.id = 0,
+	.dev = {
+		.release = i82365_device_release,
+	}
 };
 
 static int __init init_i82365(void)
@@ -1429,6 +1438,7 @@ static void __exit exit_i82365(void)
 {
     int i;
 
+    init_completion(&device_release);
     for (i = 0; i < sockets; i++) {
 	    pcmcia_unregister_socket(&socket[i].socket);
     }
@@ -1447,6 +1457,7 @@ static void __exit exit_i82365(void)
     		pnp_disable_dev(i82365_pnpdev);
 #endif
     driver_unregister(&i82365_driver);
+    wait_for_completion(&device_release);
 } /* exit_i82365 */
 
 module_init(init_i82365);
--- linux.orig/drivers/pcmcia/tcic.c
+++ linux/drivers/pcmcia/tcic.c
@@ -130,6 +130,7 @@ struct tcic_socket {
 
 static struct timer_list poll_timer;
 static int tcic_timer_pending;
+static struct completion device_release;
 
 static int sockets;
 static struct tcic_socket socket_table[2];
@@ -392,9 +393,17 @@ static struct device_driver tcic_driver 
 	.resume = tcic_drv_resume,
 };
 
+static void tcic_device_release(struct device *dev)
+{
+	complete(&device_release);
+}
+
 static struct platform_device tcic_device = {
 	.name = "tcic-pcmcia",
 	.id = 0,
+	.dev = {
+		.release = tcic_device_release,
+	}
 };
 
 
@@ -550,6 +559,7 @@ static void __exit exit_tcic(void)
 {
     int i;
 
+    init_completion(&device_release);
     del_timer_sync(&poll_timer);
     if (cs_irq != 0) {
 	tcic_aux_setw(TCIC_AUX_SYSCFG, TCIC_SYSCFG_AUTOBUSY|0x0a00);
@@ -563,6 +573,7 @@ static void __exit exit_tcic(void)
 
     platform_device_unregister(&tcic_device);
     driver_unregister(&tcic_driver);
+    wait_for_completion(&device_release);
 } /* exit_tcic */
 
 /*====================================================================*/


More information about the linux-pcmcia mailing list