Re: [RFC] class_device_add needs error checks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 25 Apr 2006 15:39:58 -0700
Greg KH <[email protected]> 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 <[email protected]>

--- 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;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux