diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2008-01-21 10:09:44 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-01-24 23:40:44 -0500 |
commit | 63b6971a0876b744e2fcf3c9df15d130501e1deb (patch) | |
tree | e5d89795dbcbc49e5685bd99a15700e58c53d95f /drivers | |
parent | 4f0146919be6bff47b5ea97252bcec0286e4dd19 (diff) |
Driver core: Cleanup get_device_parent() in device_add() and device_move()
Make setup_parent() void as get_device_parent() will always return
either a valid kobject or NULL.
Introduce cleanup_glue_dir() to drop reference grabbed on "glue"
directory by get_device_parent(). Use it for cleanup in device_move()
and device_add() on errors.
This should fix the refcounting problem reported in
http://marc.info/?l=linux-kernel&m=120052487909200&w=2
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
Cc: Dave Young <hidave.darkstar@gmail.com>
Cc: Gabor Gombas <gombasg@sztaki.hu>
Cc: Tejun Heo <htejun@gmail.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Marcel Holtmann <marcel@holtmann.org>
Cc: David Miller <davem@davemloft.net>
Cc: Kay Sievers <kay.sievers@vrfy.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/core.c | 29 |
1 files changed, 14 insertions, 15 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index d5d542db96fd..f09dde3b1e27 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -552,6 +552,8 @@ static struct kobject *get_device_parent(struct device *dev, | |||
552 | } | 552 | } |
553 | 553 | ||
554 | static inline void cleanup_device_parent(struct device *dev) {} | 554 | static inline void cleanup_device_parent(struct device *dev) {} |
555 | static inline void cleanup_glue_dir(struct device *dev, | ||
556 | struct kobject *glue_dir) {} | ||
555 | #else | 557 | #else |
556 | static struct kobject *virtual_device_parent(struct device *dev) | 558 | static struct kobject *virtual_device_parent(struct device *dev) |
557 | { | 559 | { |
@@ -616,27 +618,27 @@ static struct kobject *get_device_parent(struct device *dev, | |||
616 | return NULL; | 618 | return NULL; |
617 | } | 619 | } |
618 | 620 | ||
619 | static void cleanup_device_parent(struct device *dev) | 621 | static void cleanup_glue_dir(struct device *dev, struct kobject *glue_dir) |
620 | { | 622 | { |
621 | struct kobject *glue_dir = dev->kobj.parent; | ||
622 | |||
623 | /* see if we live in a "glue" directory */ | 623 | /* see if we live in a "glue" directory */ |
624 | if (!dev->class || glue_dir->kset != &dev->class->class_dirs) | 624 | if (!dev->class || glue_dir->kset != &dev->class->class_dirs) |
625 | return; | 625 | return; |
626 | 626 | ||
627 | kobject_put(glue_dir); | 627 | kobject_put(glue_dir); |
628 | } | 628 | } |
629 | |||
630 | static void cleanup_device_parent(struct device *dev) | ||
631 | { | ||
632 | cleanup_glue_dir(dev, dev->kobj.parent); | ||
633 | } | ||
629 | #endif | 634 | #endif |
630 | 635 | ||
631 | static int setup_parent(struct device *dev, struct device *parent) | 636 | static void setup_parent(struct device *dev, struct device *parent) |
632 | { | 637 | { |
633 | struct kobject *kobj; | 638 | struct kobject *kobj; |
634 | kobj = get_device_parent(dev, parent); | 639 | kobj = get_device_parent(dev, parent); |
635 | if (IS_ERR(kobj)) | ||
636 | return PTR_ERR(kobj); | ||
637 | if (kobj) | 640 | if (kobj) |
638 | dev->kobj.parent = kobj; | 641 | dev->kobj.parent = kobj; |
639 | return 0; | ||
640 | } | 642 | } |
641 | 643 | ||
642 | static int device_add_class_symlinks(struct device *dev) | 644 | static int device_add_class_symlinks(struct device *dev) |
@@ -784,9 +786,7 @@ int device_add(struct device *dev) | |||
784 | pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); | 786 | pr_debug("device: '%s': %s\n", dev->bus_id, __FUNCTION__); |
785 | 787 | ||
786 | parent = get_device(dev->parent); | 788 | parent = get_device(dev->parent); |
787 | error = setup_parent(dev, parent); | 789 | setup_parent(dev, parent); |
788 | if (error) | ||
789 | goto Error; | ||
790 | 790 | ||
791 | /* first, register with generic layer. */ | 791 | /* first, register with generic layer. */ |
792 | error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); | 792 | error = kobject_add(&dev->kobj, dev->kobj.parent, "%s", dev->bus_id); |
@@ -864,6 +864,7 @@ int device_add(struct device *dev) | |||
864 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); | 864 | kobject_uevent(&dev->kobj, KOBJ_REMOVE); |
865 | kobject_del(&dev->kobj); | 865 | kobject_del(&dev->kobj); |
866 | Error: | 866 | Error: |
867 | cleanup_device_parent(dev); | ||
867 | if (parent) | 868 | if (parent) |
868 | put_device(parent); | 869 | put_device(parent); |
869 | goto Done; | 870 | goto Done; |
@@ -1344,15 +1345,12 @@ int device_move(struct device *dev, struct device *new_parent) | |||
1344 | 1345 | ||
1345 | new_parent = get_device(new_parent); | 1346 | new_parent = get_device(new_parent); |
1346 | new_parent_kobj = get_device_parent (dev, new_parent); | 1347 | new_parent_kobj = get_device_parent (dev, new_parent); |
1347 | if (IS_ERR(new_parent_kobj)) { | 1348 | |
1348 | error = PTR_ERR(new_parent_kobj); | ||
1349 | put_device(new_parent); | ||
1350 | goto out; | ||
1351 | } | ||
1352 | pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, | 1349 | pr_debug("device: '%s': %s: moving to '%s'\n", dev->bus_id, |
1353 | __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>"); | 1350 | __FUNCTION__, new_parent ? new_parent->bus_id : "<NULL>"); |
1354 | error = kobject_move(&dev->kobj, new_parent_kobj); | 1351 | error = kobject_move(&dev->kobj, new_parent_kobj); |
1355 | if (error) { | 1352 | if (error) { |
1353 | cleanup_glue_dir(dev, new_parent_kobj); | ||
1356 | put_device(new_parent); | 1354 | put_device(new_parent); |
1357 | goto out; | 1355 | goto out; |
1358 | } | 1356 | } |
@@ -1375,6 +1373,7 @@ int device_move(struct device *dev, struct device *new_parent) | |||
1375 | klist_add_tail(&dev->knode_parent, | 1373 | klist_add_tail(&dev->knode_parent, |
1376 | &old_parent->klist_children); | 1374 | &old_parent->klist_children); |
1377 | } | 1375 | } |
1376 | cleanup_glue_dir(dev, new_parent_kobj); | ||
1378 | put_device(new_parent); | 1377 | put_device(new_parent); |
1379 | goto out; | 1378 | goto out; |
1380 | } | 1379 | } |