Browse Source

Driver Core: do not oops when driver_unregister() is called for unregistered drivers

We also fix a problem with cleaning up properly when initializing
drivers and devices, so checks like this will work successfully.

Portions of the patch by Linus and Greg and Ingo.

Reported-by: Ozan Çağlayan <ozan@pardus.org.tr>
Signed-off-by: Kay Sievers <kay.sievers@vrfy.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Kay Sievers 16 years ago
parent
commit
5c8563d773
3 changed files with 11 additions and 2 deletions
  1. 3 1
      drivers/base/bus.c
  2. 4 1
      drivers/base/core.c
  3. 4 0
      drivers/base/driver.c

+ 3 - 1
drivers/base/bus.c

@@ -700,8 +700,10 @@ int bus_add_driver(struct device_driver *drv)
 	}
 	}
 
 
 	kobject_uevent(&priv->kobj, KOBJ_ADD);
 	kobject_uevent(&priv->kobj, KOBJ_ADD);
-	return error;
+	return 0;
 out_unregister:
 out_unregister:
+	kfree(drv->p);
+	drv->p = NULL;
 	kobject_put(&priv->kobj);
 	kobject_put(&priv->kobj);
 out_put_bus:
 out_put_bus:
 	bus_put(bus);
 	bus_put(bus);

+ 4 - 1
drivers/base/core.c

@@ -879,7 +879,7 @@ int device_add(struct device *dev)
 	}
 	}
 
 
 	if (!dev_name(dev))
 	if (!dev_name(dev))
-		goto done;
+		goto name_error;
 
 
 	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 	pr_debug("device: '%s': %s\n", dev_name(dev), __func__);
 
 
@@ -978,6 +978,9 @@ done:
 	cleanup_device_parent(dev);
 	cleanup_device_parent(dev);
 	if (parent)
 	if (parent)
 		put_device(parent);
 		put_device(parent);
+name_error:
+	kfree(dev->p);
+	dev->p = NULL;
 	goto done;
 	goto done;
 }
 }
 
 

+ 4 - 0
drivers/base/driver.c

@@ -257,6 +257,10 @@ EXPORT_SYMBOL_GPL(driver_register);
  */
  */
 void driver_unregister(struct device_driver *drv)
 void driver_unregister(struct device_driver *drv)
 {
 {
+	if (!drv || !drv->p) {
+		WARN(1, "Unexpected driver unregister!\n");
+		return;
+	}
 	driver_remove_groups(drv, drv->groups);
 	driver_remove_groups(drv, drv->groups);
 	bus_remove_driver(drv);
 	bus_remove_driver(drv);
 }
 }