diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2007-07-18 04:43:47 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-07-18 18:49:50 -0400 |
commit | 2ee97caf0a6602f749ddbfdb1449e383e1212707 (patch) | |
tree | 6f0fb8f1c856aeb20149a73b1cb85ba943d11ce8 /drivers | |
parent | be3884943674f8ee7656b1d8b71c087ec900c836 (diff) |
Driver core: check return code of sysfs_create_link()
Check for return value of sysfs_create_link() in device_add() and
device_rename(). Add helper functions device_add_class_symlinks() and
device_remove_class_symlinks() to make the code easier to read.
[akpm@linux-foundation.org: fix unused var warnings]
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Acked-by: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/core.c | 145 |
1 files changed, 105 insertions, 40 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 91a0367d583e..3599ab2506d2 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -660,6 +660,82 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
660 | return 0; | 660 | return 0; |
661 | } | 661 | } |
662 | 662 | ||
663 | static int device_add_class_symlinks(struct device *dev) | ||
664 | { | ||
665 | int error; | ||
666 | |||
667 | if (!dev->class) | ||
668 | return 0; | ||
669 | error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | ||
670 | "subsystem"); | ||
671 | if (error) | ||
672 | goto out; | ||
673 | /* | ||
674 | * If this is not a "fake" compatible device, then create the | ||
675 | * symlink from the class to the device. | ||
676 | */ | ||
677 | if (dev->kobj.parent != &dev->class->subsys.kobj) { | ||
678 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | ||
679 | dev->bus_id); | ||
680 | if (error) | ||
681 | goto out_subsys; | ||
682 | } | ||
683 | /* only bus-device parents get a "device"-link */ | ||
684 | if (dev->parent && dev->parent->bus) { | ||
685 | error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
686 | "device"); | ||
687 | if (error) | ||
688 | goto out_busid; | ||
689 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
690 | { | ||
691 | char * class_name = make_class_name(dev->class->name, | ||
692 | &dev->kobj); | ||
693 | if (class_name) | ||
694 | error = sysfs_create_link(&dev->parent->kobj, | ||
695 | &dev->kobj, class_name); | ||
696 | kfree(class_name); | ||
697 | if (error) | ||
698 | goto out_device; | ||
699 | } | ||
700 | #endif | ||
701 | } | ||
702 | return 0; | ||
703 | |||
704 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
705 | out_device: | ||
706 | if (dev->parent) | ||
707 | sysfs_remove_link(&dev->kobj, "device"); | ||
708 | #endif | ||
709 | out_busid: | ||
710 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
711 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
712 | out_subsys: | ||
713 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
714 | out: | ||
715 | return error; | ||
716 | } | ||
717 | |||
718 | static void device_remove_class_symlinks(struct device *dev) | ||
719 | { | ||
720 | if (!dev->class) | ||
721 | return; | ||
722 | if (dev->parent) { | ||
723 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
724 | char *class_name; | ||
725 | |||
726 | class_name = make_class_name(dev->class->name, &dev->kobj); | ||
727 | if (class_name) { | ||
728 | sysfs_remove_link(&dev->parent->kobj, class_name); | ||
729 | kfree(class_name); | ||
730 | } | ||
731 | #endif | ||
732 | sysfs_remove_link(&dev->kobj, "device"); | ||
733 | } | ||
734 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
735 | sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); | ||
736 | sysfs_remove_link(&dev->kobj, "subsystem"); | ||
737 | } | ||
738 | |||
663 | /** | 739 | /** |
664 | * device_add - add device to device hierarchy. | 740 | * device_add - add device to device hierarchy. |
665 | * @dev: device. | 741 | * @dev: device. |
@@ -674,7 +750,6 @@ static int setup_parent(struct device *dev, struct device *parent) | |||
674 | int device_add(struct device *dev) | 750 | int device_add(struct device *dev) |
675 | { | 751 | { |
676 | struct device *parent = NULL; | 752 | struct device *parent = NULL; |
677 | char *class_name = NULL; | ||
678 | struct class_interface *class_intf; | 753 | struct class_interface *class_intf; |
679 | int error = -EINVAL; | 754 | int error = -EINVAL; |
680 | 755 | ||
@@ -714,27 +789,9 @@ int device_add(struct device *dev) | |||
714 | goto ueventattrError; | 789 | goto ueventattrError; |
715 | } | 790 | } |
716 | 791 | ||
717 | if (dev->class) { | 792 | error = device_add_class_symlinks(dev); |
718 | sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, | 793 | if (error) |
719 | "subsystem"); | 794 | goto SymlinkError; |
720 | /* If this is not a "fake" compatible device, then create the | ||
721 | * symlink from the class to the device. */ | ||
722 | if (dev->kobj.parent != &dev->class->subsys.kobj) | ||
723 | sysfs_create_link(&dev->class->subsys.kobj, | ||
724 | &dev->kobj, dev->bus_id); | ||
725 | if (parent) { | ||
726 | sysfs_create_link(&dev->kobj, &dev->parent->kobj, | ||
727 | "device"); | ||
728 | #ifdef CONFIG_SYSFS_DEPRECATED | ||
729 | class_name = make_class_name(dev->class->name, | ||
730 | &dev->kobj); | ||
731 | if (class_name) | ||
732 | sysfs_create_link(&dev->parent->kobj, | ||
733 | &dev->kobj, class_name); | ||
734 | #endif | ||
735 | } | ||
736 | } | ||
737 | |||
738 | error = device_add_attrs(dev); | 795 | error = device_add_attrs(dev); |
739 | if (error) | 796 | if (error) |
740 | goto AttrsError; | 797 | goto AttrsError; |
@@ -761,7 +818,6 @@ int device_add(struct device *dev) | |||
761 | up(&dev->class->sem); | 818 | up(&dev->class->sem); |
762 | } | 819 | } |
763 | Done: | 820 | Done: |
764 | kfree(class_name); | ||
765 | put_device(dev); | 821 | put_device(dev); |
766 | return error; | 822 | return error; |
767 | BusError: | 823 | BusError: |
@@ -772,6 +828,8 @@ int device_add(struct device *dev) | |||
772 | BUS_NOTIFY_DEL_DEVICE, dev); | 828 | BUS_NOTIFY_DEL_DEVICE, dev); |
773 | device_remove_attrs(dev); | 829 | device_remove_attrs(dev); |
774 | AttrsError: | 830 | AttrsError: |
831 | device_remove_class_symlinks(dev); | ||
832 | SymlinkError: | ||
775 | if (MAJOR(dev->devt)) | 833 | if (MAJOR(dev->devt)) |
776 | device_remove_file(dev, &devt_attr); | 834 | device_remove_file(dev, &devt_attr); |
777 | 835 | ||
@@ -1156,7 +1214,7 @@ int device_rename(struct device *dev, char *new_name) | |||
1156 | { | 1214 | { |
1157 | char *old_class_name = NULL; | 1215 | char *old_class_name = NULL; |
1158 | char *new_class_name = NULL; | 1216 | char *new_class_name = NULL; |
1159 | char *old_symlink_name = NULL; | 1217 | char *old_device_name = NULL; |
1160 | int error; | 1218 | int error; |
1161 | 1219 | ||
1162 | dev = get_device(dev); | 1220 | dev = get_device(dev); |
@@ -1170,42 +1228,49 @@ int device_rename(struct device *dev, char *new_name) | |||
1170 | old_class_name = make_class_name(dev->class->name, &dev->kobj); | 1228 | old_class_name = make_class_name(dev->class->name, &dev->kobj); |
1171 | #endif | 1229 | #endif |
1172 | 1230 | ||
1173 | if (dev->class) { | 1231 | old_device_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); |
1174 | old_symlink_name = kmalloc(BUS_ID_SIZE, GFP_KERNEL); | 1232 | if (!old_device_name) { |
1175 | if (!old_symlink_name) { | 1233 | error = -ENOMEM; |
1176 | error = -ENOMEM; | 1234 | goto out; |
1177 | goto out_free_old_class; | ||
1178 | } | ||
1179 | strlcpy(old_symlink_name, dev->bus_id, BUS_ID_SIZE); | ||
1180 | } | 1235 | } |
1181 | 1236 | strlcpy(old_device_name, dev->bus_id, BUS_ID_SIZE); | |
1182 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); | 1237 | strlcpy(dev->bus_id, new_name, BUS_ID_SIZE); |
1183 | 1238 | ||
1184 | error = kobject_rename(&dev->kobj, new_name); | 1239 | error = kobject_rename(&dev->kobj, new_name); |
1240 | if (error) { | ||
1241 | strlcpy(dev->bus_id, old_device_name, BUS_ID_SIZE); | ||
1242 | goto out; | ||
1243 | } | ||
1185 | 1244 | ||
1186 | #ifdef CONFIG_SYSFS_DEPRECATED | 1245 | #ifdef CONFIG_SYSFS_DEPRECATED |
1187 | if (old_class_name) { | 1246 | if (old_class_name) { |
1188 | new_class_name = make_class_name(dev->class->name, &dev->kobj); | 1247 | new_class_name = make_class_name(dev->class->name, &dev->kobj); |
1189 | if (new_class_name) { | 1248 | if (new_class_name) { |
1190 | sysfs_create_link(&dev->parent->kobj, &dev->kobj, | 1249 | error = sysfs_create_link(&dev->parent->kobj, |
1191 | new_class_name); | 1250 | &dev->kobj, new_class_name); |
1251 | if (error) | ||
1252 | goto out; | ||
1192 | sysfs_remove_link(&dev->parent->kobj, old_class_name); | 1253 | sysfs_remove_link(&dev->parent->kobj, old_class_name); |
1193 | } | 1254 | } |
1194 | } | 1255 | } |
1195 | #endif | 1256 | #endif |
1196 | 1257 | ||
1197 | if (dev->class) { | 1258 | if (dev->class) { |
1198 | sysfs_remove_link(&dev->class->subsys.kobj, | 1259 | sysfs_remove_link(&dev->class->subsys.kobj, old_device_name); |
1199 | old_symlink_name); | 1260 | error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, |
1200 | sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, | 1261 | dev->bus_id); |
1201 | dev->bus_id); | 1262 | if (error) { |
1263 | /* Uh... how to unravel this if restoring can fail? */ | ||
1264 | dev_err(dev, "%s: sysfs_create_symlink failed (%d)\n", | ||
1265 | __FUNCTION__, error); | ||
1266 | } | ||
1202 | } | 1267 | } |
1268 | out: | ||
1203 | put_device(dev); | 1269 | put_device(dev); |
1204 | 1270 | ||
1205 | kfree(new_class_name); | 1271 | kfree(new_class_name); |
1206 | kfree(old_symlink_name); | ||
1207 | out_free_old_class: | ||
1208 | kfree(old_class_name); | 1272 | kfree(old_class_name); |
1273 | kfree(old_device_name); | ||
1209 | 1274 | ||
1210 | return error; | 1275 | return error; |
1211 | } | 1276 | } |