Commit b7fe4a60 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Greg Kroah-Hartman

[PATCH] Driver core: class_device_add needs error checks

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: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 3dda4e37
...@@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev) ...@@ -535,18 +535,22 @@ int class_device_add(struct class_device *class_dev)
return -EINVAL; return -EINVAL;
if (!strlen(class_dev->class_id)) if (!strlen(class_dev->class_id))
goto register_done; goto out1;
parent_class = class_get(class_dev->class); parent_class = class_get(class_dev->class);
if (!parent_class) if (!parent_class)
goto register_done; goto out1;
parent_class_dev = class_device_get(class_dev->parent); parent_class_dev = class_device_get(class_dev->parent);
pr_debug("CLASS: registering class device: ID = '%s'\n", pr_debug("CLASS: registering class device: ID = '%s'\n",
class_dev->class_id); class_dev->class_id);
/* first, register with generic layer. */ /* 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) if (parent_class_dev)
class_dev->kobj.parent = &parent_class_dev->kobj; class_dev->kobj.parent = &parent_class_dev->kobj;
else else
...@@ -554,41 +558,56 @@ int class_device_add(struct class_device *class_dev) ...@@ -554,41 +558,56 @@ int class_device_add(struct class_device *class_dev)
error = kobject_add(&class_dev->kobj); error = kobject_add(&class_dev->kobj);
if (error) if (error)
goto register_done; goto out2;
/* add the needed attributes to this device */ /* add the needed attributes to this device */
class_dev->uevent_attr.attr.name = "uevent"; class_dev->uevent_attr.attr.name = "uevent";
class_dev->uevent_attr.attr.mode = S_IWUSR; class_dev->uevent_attr.attr.mode = S_IWUSR;
class_dev->uevent_attr.attr.owner = parent_class->owner; class_dev->uevent_attr.attr.owner = parent_class->owner;
class_dev->uevent_attr.store = store_uevent; 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)) { if (MAJOR(class_dev->devt)) {
struct class_device_attribute *attr; struct class_device_attribute *attr;
attr = kzalloc(sizeof(*attr), GFP_KERNEL); attr = kzalloc(sizeof(*attr), GFP_KERNEL);
if (!attr) { if (!attr) {
error = -ENOMEM; error = -ENOMEM;
kobject_del(&class_dev->kobj); goto out4;
goto register_done;
} }
attr->attr.name = "dev"; attr->attr.name = "dev";
attr->attr.mode = S_IRUGO; attr->attr.mode = S_IRUGO;
attr->attr.owner = parent_class->owner; attr->attr.owner = parent_class->owner;
attr->show = show_dev; 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_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) { if (class_dev->dev) {
class_name = make_class_name(class_dev); class_name = make_class_name(class_dev);
sysfs_create_link(&class_dev->kobj, error = sysfs_create_link(&class_dev->kobj,
&class_dev->dev->kobj, "device"); &class_dev->dev->kobj, "device");
sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj, if (error)
goto out6;
error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
class_name); 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); kobject_uevent(&class_dev->kobj, KOBJ_ADD);
...@@ -601,11 +620,28 @@ int class_device_add(struct class_device *class_dev) ...@@ -601,11 +620,28 @@ int class_device_add(struct class_device *class_dev)
} }
up(&parent_class->sem); up(&parent_class->sem);
register_done: goto out1;
if (error) {
class_put(parent_class); 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_device_put(parent_class_dev);
} class_put(parent_class);
out1:
class_device_put(class_dev); class_device_put(class_dev);
kfree(class_name); kfree(class_name);
return error; return error;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment