All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC] class_device_add needs error checks
@ 2006-04-21 20:40 Stephen Hemminger
  2006-04-25 22:39 ` Greg KH
  0 siblings, 1 reply; 3+ messages in thread
From: Stephen Hemminger @ 2006-04-21 20:40 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel

class_device_add needs to check the return value of all the setup functions
it calls. It doesn't handle out of memory well. 

This is not complete, probably more needs to be done, and the unwind
may not work right.

--- linux-2.6.orig/drivers/base/class.c	2006-04-21 12:21:21.000000000 -0700
+++ linux-2.6/drivers/base/class.c	2006-04-21 12:41:48.000000000 -0700
@@ -546,7 +546,10 @@
 		 class_dev->class_id);
 
 	/* first, register with generic layer. */
-	kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+	error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+	if (error)
+		goto register_done;
+
 	if (parent_class_dev)
 		class_dev->kobj.parent = &parent_class_dev->kobj;
 	else
@@ -561,34 +564,49 @@
 	class_dev->uevent_attr.attr.mode = S_IWUSR;
 	class_dev->uevent_attr.attr.owner = parent_class->owner;
 	class_dev->uevent_attr.store = store_uevent;
-	class_device_create_file(class_dev, &class_dev->uevent_attr);
+	error = class_device_create_file(class_dev, &class_dev->uevent_attr);
+	if (error)
+		goto register_done;
 
 	if (MAJOR(class_dev->devt)) {
 		struct class_device_attribute *attr;
 		attr = kzalloc(sizeof(*attr), GFP_KERNEL);
 		if (!attr) {
 			error = -ENOMEM;
-			kobject_del(&class_dev->kobj);
 			goto register_done;
 		}
 		attr->attr.name = "dev";
 		attr->attr.mode = S_IRUGO;
 		attr->attr.owner = parent_class->owner;
 		attr->show = show_dev;
-		class_device_create_file(class_dev, attr);
+		error = class_device_create_file(class_dev, attr);
+		if (error) {
+			kfree(attr);
+			goto register_done;
+		}
+
 		class_dev->devt_attr = attr;
 	}
 
-	class_device_add_attrs(class_dev);
+	error = class_device_add_attrs(class_dev);
+	if (error)
+		goto register_done;
+
 	if (class_dev->dev) {
 		class_name = make_class_name(class_dev);
-		sysfs_create_link(&class_dev->kobj,
-				  &class_dev->dev->kobj, "device");
-		sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-				  class_name);
+		error = sysfs_create_link(&class_dev->kobj,
+					  &class_dev->dev->kobj, "device");
+		if (error)
+			goto register_done;
+		error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+					  class_name);
+		if (error)
+			goto register_done;
 	}
 
-	class_device_add_groups(class_dev);
+	error = class_device_add_groups(class_dev);
+	if (error)
+		goto register_done;
 
 	kobject_uevent(&class_dev->kobj, KOBJ_ADD);
 
@@ -603,6 +621,15 @@
 
  register_done:
 	if (error) {
+		sysfs_remove_link(&class_dev->kobj, "device");
+		sysfs_remove_link(&class_dev->dev->kobj, class_name);
+		class_device_remove_attrs(class_dev);
+		class_device_remove_file(class_dev, &class_dev->uevent_attr);
+		if (class_dev->devt_attr)
+			class_device_remove_file(class_dev, class_dev->devt_attr);
+
+		if (atomic_read(&class_dev->kobj.kref.refcount))
+			kobject_del(&class_dev->kobj);
 		class_put(parent_class);
 		class_device_put(parent_class_dev);
 	}

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] class_device_add needs error checks
  2006-04-21 20:40 [RFC] class_device_add needs error checks Stephen Hemminger
@ 2006-04-25 22:39 ` Greg KH
  2006-04-26 16:53   ` Stephen Hemminger
  0 siblings, 1 reply; 3+ messages in thread
From: Greg KH @ 2006-04-25 22:39 UTC (permalink / raw)
  To: Stephen Hemminger; +Cc: linux-kernel

On Fri, Apr 21, 2006 at 01:40:27PM -0700, Stephen Hemminger wrote:
> +		if (atomic_read(&class_dev->kobj.kref.refcount))
> +			kobject_del(&class_dev->kobj);

Yeah, we can't do this, we should not be mucking around in the kref core
like this.

Are you having problems where class_device_add() should be failing and
it isn't?

Other than the above, the patch almost looked good :)

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [RFC] class_device_add needs error checks
  2006-04-25 22:39 ` Greg KH
@ 2006-04-26 16:53   ` Stephen Hemminger
  0 siblings, 0 replies; 3+ messages in thread
From: Stephen Hemminger @ 2006-04-26 16:53 UTC (permalink / raw)
  To: Greg KH; +Cc: linux-kernel

On Tue, 25 Apr 2006 15:39:58 -0700
Greg KH <greg@kroah.com> wrote:

> On Fri, Apr 21, 2006 at 01:40:27PM -0700, Stephen Hemminger wrote:
> > +		if (atomic_read(&class_dev->kobj.kref.refcount))
> > +			kobject_del(&class_dev->kobj);
> 
> Yeah, we can't do this, we should not be mucking around in the kref core
> like this.
> 
> Are you having problems where class_device_add() should be failing and
> it isn't?

No, never seen it happen; just that the code is ignoring a lot of
possible out of memory conditions.

The following has better unwind..
-----------------------------------
class_device_add needs to check the return value of all the setup it
does. It doesn't handle out of memory well. This is not complete, probably
more needs to be done.

Signed-off-by: Stephen Hemminger <shemminger@osdl.org>

--- linux-2.6.orig/drivers/base/class.c	2006-04-25 15:47:32.000000000 -0700
+++ linux-2.6/drivers/base/class.c	2006-04-26 09:50:34.000000000 -0700
@@ -535,18 +535,22 @@
 		return -EINVAL;
 
 	if (!strlen(class_dev->class_id))
-		goto register_done;
+		goto out1;
 
 	parent_class = class_get(class_dev->class);
 	if (!parent_class)
-		goto register_done;
+		goto out1;
+
 	parent_class_dev = class_device_get(class_dev->parent);
 
 	pr_debug("CLASS: registering class device: ID = '%s'\n",
 		 class_dev->class_id);
 
 	/* first, register with generic layer. */
-	kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+	error = kobject_set_name(&class_dev->kobj, "%s", class_dev->class_id);
+	if (error)
+		goto out2;
+
 	if (parent_class_dev)
 		class_dev->kobj.parent = &parent_class_dev->kobj;
 	else
@@ -554,41 +558,56 @@
 
 	error = kobject_add(&class_dev->kobj);
 	if (error)
-		goto register_done;
+		goto out2;
 
 	/* add the needed attributes to this device */
 	class_dev->uevent_attr.attr.name = "uevent";
 	class_dev->uevent_attr.attr.mode = S_IWUSR;
 	class_dev->uevent_attr.attr.owner = parent_class->owner;
 	class_dev->uevent_attr.store = store_uevent;
-	class_device_create_file(class_dev, &class_dev->uevent_attr);
+	error = class_device_create_file(class_dev, &class_dev->uevent_attr);
+	if (error)
+		goto out3;
 
 	if (MAJOR(class_dev->devt)) {
 		struct class_device_attribute *attr;
 		attr = kzalloc(sizeof(*attr), GFP_KERNEL);
 		if (!attr) {
 			error = -ENOMEM;
-			kobject_del(&class_dev->kobj);
-			goto register_done;
+			goto out4;
 		}
 		attr->attr.name = "dev";
 		attr->attr.mode = S_IRUGO;
 		attr->attr.owner = parent_class->owner;
 		attr->show = show_dev;
-		class_device_create_file(class_dev, attr);
+		error = class_device_create_file(class_dev, attr);
+		if (error) {
+			kfree(attr);
+			goto out4;
+		}
+
 		class_dev->devt_attr = attr;
 	}
 
-	class_device_add_attrs(class_dev);
+	error = class_device_add_attrs(class_dev);
+	if (error)
+		goto out5;
+
 	if (class_dev->dev) {
 		class_name = make_class_name(class_dev);
-		sysfs_create_link(&class_dev->kobj,
-				  &class_dev->dev->kobj, "device");
-		sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-				  class_name);
+		error = sysfs_create_link(&class_dev->kobj,
+					  &class_dev->dev->kobj, "device");
+		if (error)
+			goto out6;
+		error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
+					  class_name);
+		if (error)
+			goto out7;
 	}
 
-	class_device_add_groups(class_dev);
+	error = class_device_add_groups(class_dev);
+	if (error)
+		goto out8;
 
 	kobject_uevent(&class_dev->kobj, KOBJ_ADD);
 
@@ -601,11 +620,28 @@
 	}
 	up(&parent_class->sem);
 
- register_done:
-	if (error) {
-		class_put(parent_class);
+	return 0;
+
+ out8:
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, class_name);
+ out7:
+	if (class_dev->dev)
+		sysfs_remove_link(&class_dev->kobj, "device");
+ out6:
+	class_device_remove_attrs(class_dev);
+ out5:
+	if (class_dev->devt_attr)
+		class_device_remove_file(class_dev, class_dev->devt_attr);
+ out4:
+	class_device_remove_file(class_dev, &class_dev->uevent_attr);
+ out3:
+	kobject_del(&class_dev->kobj);
+ out2:
+	if(parent_class_dev)
 		class_device_put(parent_class_dev);
-	}
+	class_put(parent_class);
+ out1:
 	class_device_put(class_dev);
 	kfree(class_name);
 	return error;

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2006-04-26 16:53 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2006-04-21 20:40 [RFC] class_device_add needs error checks Stephen Hemminger
2006-04-25 22:39 ` Greg KH
2006-04-26 16:53   ` Stephen Hemminger

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.