[PATCH] fix ds.c memory leak

Daniel Ritz daniel.ritz at gmx.ch
Sun Jan 4 00:53:28 GMT 2004


bind_request() leaks memory if driver->attach() fails. also the module is still
referenced (b->driver = driver) while doing a module_put().
and driver->use_count would be wrong.
the patch also undoes what pcmcia_bind_device() did when driver->attach() fails.
it fixes another 'memory leak'. (yes, it's ugly, but ds.c is the only caller of
pcmcia_bind_device() so it's not too bad and since it's too late for massive
cleanup work...)

against 2.6.1-rc1.

--- 1.39/drivers/pcmcia/ds.c	Sat Sep 27 05:11:05 2003
+++ edited/drivers/pcmcia/ds.c	Sat Jan  3 16:36:16 2004
@@ -360,36 +360,43 @@
 	cs_error(NULL, BindDevice, ret);
 	printk(KERN_NOTICE "ds: unable to bind '%s' to socket %d\n",
 	       (char *)dev_info, s->parent->sock);
-	module_put(driver->owner);
-	return -ENODEV;
+	ret = -ENODEV;
+	goto out_put;
     }
 
     /* Add binding to list for this socket */
-    driver->use_count++;
-    b = kmalloc(sizeof(socket_bind_t), GFP_KERNEL);
-    if (!b) 
-    {
-    	driver->use_count--;
-	module_put(driver->owner);
-	return -ENOMEM;    
+    b = kmalloc(sizeof(*b), GFP_KERNEL);
+    if (!b) {
+	    ret = -ENOMEM;
+	    goto out_unbind;
     }
     b->driver = driver;
     b->function = bind_info->function;
     b->instance = NULL;
-    b->next = s->bind;
-    s->bind = b;
     
     if (driver->attach) {
 	b->instance = driver->attach();
 	if (b->instance == NULL) {
 	    printk(KERN_NOTICE "ds: unable to create instance "
 		   "of '%s'!\n", (char *)bind_info->dev_info);
-	    module_put(driver->owner);
-	    return -ENODEV;
+	    ret = -ENODEV;
+	    goto out_free;
 	}
     }
+
+    b->next = s->bind;
+    s->bind = b;
+    driver->use_count++;
     
     return 0;
+
+out_free:
+	kfree(b);
+out_unbind:
+	pcmcia_bind_device_undo(&bind_req);
+out_put:
+	module_put(driver->owner);
+	return ret;
 } /* bind_request */
 
 /*====================================================================*/
@@ -873,6 +880,7 @@
 	ret = pcmcia_register_client(&s->handle, &client_reg);
 	if (ret != CS_SUCCESS) {
 		cs_error(NULL, RegisterClient, ret);
+		pcmcia_bind_device_undo(&bind);
 		kfree(s);
 		return -EINVAL;
 	}
--- 1.5/include/pcmcia/cs.h	Sat Sep 27 05:15:09 2003
+++ edited/include/pcmcia/cs.h	Sat Jan  3 16:31:47 2004
@@ -429,6 +429,7 @@
 
 int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
 int pcmcia_bind_device(bind_req_t *req);
+int pcmcia_bind_device_undo(bind_req_t *req);
 int pcmcia_bind_mtd(mtd_bind_t *req);
 int pcmcia_deregister_client(client_handle_t handle);
 int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
--- 1.68/drivers/pcmcia/cs.c	Tue Dec 30 19:35:32 2003
+++ edited/drivers/pcmcia/cs.c	Sat Jan  3 17:57:06 2004
@@ -1015,6 +1015,24 @@
     return CS_SUCCESS;
 } /* bind_device */
 
+/* undoes a previous call to pcmcia_bind_device() */
+int pcmcia_bind_device_undo(bind_req_t *req)
+{
+	struct pcmcia_socket *s;
+	client_t *client;
+	
+	s = req->Socket;
+	if (!s)
+		return CS_BAD_SOCKET;
+
+	client = s->clients;
+	s->clients = client->next;
+
+	kfree(client);
+	return CS_SUCCESS;
+}
+
+
 /*======================================================================
 
     Bind_mtd() associates a device driver with a particular memory
@@ -2441,6 +2459,7 @@
 EXPORT_SYMBOL(pcmcia_access_configuration_register);
 EXPORT_SYMBOL(pcmcia_adjust_resource_info);
 EXPORT_SYMBOL(pcmcia_bind_device);
+EXPORT_SYMBOL(pcmcia_bind_device_undo);
 EXPORT_SYMBOL(pcmcia_bind_mtd);
 EXPORT_SYMBOL(pcmcia_check_erase_queue);
 EXPORT_SYMBOL(pcmcia_close_memory);




More information about the linux-pcmcia mailing list