aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2007-11-21 11:29:15 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-01-24 23:40:36 -0500
commitda231fd5d113ab6da5dab7a2d2c38d0a540f939c (patch)
treefbaa6dfe56d544af0edc3e01633006515c2e582d /drivers/base/core.c
parentef2c51746dc89c2326ce522f8fb8a57695780e75 (diff)
Driver core: fix class glue dir cleanup logic
We should remove the glue directory between the class and the bus device _after_ we sent out the 'remove' event for the device, otherwise the parent relationship is no longer valid, and composing the path with deleted sysfs entries will not work. Cc: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r--drivers/base/core.c206
1 files changed, 94 insertions, 112 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 22fdf320a2a6..13cae18936c5 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -18,7 +18,7 @@
18#include <linux/string.h> 18#include <linux/string.h>
19#include <linux/kdev_t.h> 19#include <linux/kdev_t.h>
20#include <linux/notifier.h> 20#include <linux/notifier.h>
21 21#include <linux/genhd.h>
22#include <asm/semaphore.h> 22#include <asm/semaphore.h>
23 23
24#include "base.h" 24#include "base.h"
@@ -538,22 +538,20 @@ void device_initialize(struct device *dev)
538} 538}
539 539
540#ifdef CONFIG_SYSFS_DEPRECATED 540#ifdef CONFIG_SYSFS_DEPRECATED
541static struct kobject * get_device_parent(struct device *dev, 541static struct kobject *get_device_parent(struct device *dev,
542 struct device *parent) 542 struct device *parent)
543{ 543{
544 /* 544 /* class devices without a parent live in /sys/class/<classname>/ */
545 * Set the parent to the class, not the parent device
546 * for topmost devices in class hierarchy.
547 * This keeps sysfs from having a symlink to make old
548 * udevs happy
549 */
550 if (dev->class && (!parent || parent->class != dev->class)) 545 if (dev->class && (!parent || parent->class != dev->class))
551 return &dev->class->subsys.kobj; 546 return &dev->class->subsys.kobj;
547 /* all other devices keep their parent */
552 else if (parent) 548 else if (parent)
553 return &parent->kobj; 549 return &parent->kobj;
554 550
555 return NULL; 551 return NULL;
556} 552}
553
554static inline void cleanup_device_parent(struct device *dev) {}
557#else 555#else
558static struct kobject *virtual_device_parent(struct device *dev) 556static struct kobject *virtual_device_parent(struct device *dev)
559{ 557{
@@ -566,8 +564,8 @@ static struct kobject *virtual_device_parent(struct device *dev)
566 return virtual_dir; 564 return virtual_dir;
567} 565}
568 566
569static struct kobject * get_device_parent(struct device *dev, 567static struct kobject *get_device_parent(struct device *dev,
570 struct device *parent) 568 struct device *parent)
571{ 569{
572 int retval; 570 int retval;
573 571
@@ -618,6 +616,34 @@ static struct kobject * get_device_parent(struct device *dev,
618 return &parent->kobj; 616 return &parent->kobj;
619 return NULL; 617 return NULL;
620} 618}
619
620static void cleanup_device_parent(struct device *dev)
621{
622 struct device *d;
623 int other = 0;
624
625 if (!dev->class)
626 return;
627
628 /* see if we live in a parent class directory */
629 if (dev->kobj.parent->kset != &dev->class->class_dirs)
630 return;
631
632 /* if we are the last child of our class, delete the directory */
633 down(&dev->class->sem);
634 list_for_each_entry(d, &dev->class->devices, node) {
635 if (d == dev)
636 continue;
637 if (d->kobj.parent == dev->kobj.parent) {
638 other = 1;
639 break;
640 }
641 }
642 if (!other)
643 kobject_del(dev->kobj.parent);
644 kobject_put(dev->kobj.parent);
645 up(&dev->class->sem);
646}
621#endif 647#endif
622 648
623static int setup_parent(struct device *dev, struct device *parent) 649static int setup_parent(struct device *dev, struct device *parent)
@@ -637,65 +663,74 @@ static int device_add_class_symlinks(struct device *dev)
637 663
638 if (!dev->class) 664 if (!dev->class)
639 return 0; 665 return 0;
666
640 error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, 667 error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj,
641 "subsystem"); 668 "subsystem");
642 if (error) 669 if (error)
643 goto out; 670 goto out;
644 /* 671
645 * If this is not a "fake" compatible device, then create the 672#ifdef CONFIG_SYSFS_DEPRECATED
646 * symlink from the class to the device. 673 /* stacked class devices need a symlink in the class directory */
647 */
648 if (dev->kobj.parent != &dev->class->subsys.kobj) { 674 if (dev->kobj.parent != &dev->class->subsys.kobj) {
649 error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, 675 error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
650 dev->bus_id); 676 dev->bus_id);
651 if (error) 677 if (error)
652 goto out_subsys; 678 goto out_subsys;
653 } 679 }
680
654 if (dev->parent) { 681 if (dev->parent) {
655#ifdef CONFIG_SYSFS_DEPRECATED 682 struct device *parent = dev->parent;
656 { 683 char *class_name;
657 struct device *parent = dev->parent;
658 char *class_name;
659
660 /*
661 * In old sysfs stacked class devices had 'device'
662 * link pointing to real device instead of parent
663 */
664 while (parent->class && !parent->bus && parent->parent)
665 parent = parent->parent;
666
667 error = sysfs_create_link(&dev->kobj,
668 &parent->kobj,
669 "device");
670 if (error)
671 goto out_busid;
672 684
673 class_name = make_class_name(dev->class->name, 685 /*
674 &dev->kobj); 686 * stacked class devices have the 'device' link
675 if (class_name) 687 * pointing to the bus device instead of the parent
676 error = sysfs_create_link(&dev->parent->kobj, 688 */
677 &dev->kobj, class_name); 689 while (parent->class && !parent->bus && parent->parent)
678 kfree(class_name); 690 parent = parent->parent;
679 if (error) 691
680 goto out_device; 692 error = sysfs_create_link(&dev->kobj,
681 } 693 &parent->kobj,
682#else
683 error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
684 "device"); 694 "device");
685 if (error) 695 if (error)
686 goto out_busid; 696 goto out_busid;
687#endif 697
698 class_name = make_class_name(dev->class->name,
699 &dev->kobj);
700 if (class_name)
701 error = sysfs_create_link(&dev->parent->kobj,
702 &dev->kobj, class_name);
703 kfree(class_name);
704 if (error)
705 goto out_device;
688 } 706 }
689 return 0; 707 return 0;
690 708
691#ifdef CONFIG_SYSFS_DEPRECATED
692out_device: 709out_device:
693 if (dev->parent) 710 if (dev->parent)
694 sysfs_remove_link(&dev->kobj, "device"); 711 sysfs_remove_link(&dev->kobj, "device");
695#endif
696out_busid: 712out_busid:
697 if (dev->kobj.parent != &dev->class->subsys.kobj) 713 if (dev->kobj.parent != &dev->class->subsys.kobj)
698 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 714 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
715#else
716 /* link in the class directory pointing to the device */
717 error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj,
718 dev->bus_id);
719 if (error)
720 goto out_subsys;
721
722 if (dev->parent) {
723 error = sysfs_create_link(&dev->kobj, &dev->parent->kobj,
724 "device");
725 if (error)
726 goto out_busid;
727 }
728 return 0;
729
730out_busid:
731 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
732#endif
733
699out_subsys: 734out_subsys:
700 sysfs_remove_link(&dev->kobj, "subsystem"); 735 sysfs_remove_link(&dev->kobj, "subsystem");
701out: 736out:
@@ -706,8 +741,9 @@ static void device_remove_class_symlinks(struct device *dev)
706{ 741{
707 if (!dev->class) 742 if (!dev->class)
708 return; 743 return;
709 if (dev->parent) { 744
710#ifdef CONFIG_SYSFS_DEPRECATED 745#ifdef CONFIG_SYSFS_DEPRECATED
746 if (dev->parent) {
711 char *class_name; 747 char *class_name;
712 748
713 class_name = make_class_name(dev->class->name, &dev->kobj); 749 class_name = make_class_name(dev->class->name, &dev->kobj);
@@ -715,11 +751,18 @@ static void device_remove_class_symlinks(struct device *dev)
715 sysfs_remove_link(&dev->parent->kobj, class_name); 751 sysfs_remove_link(&dev->parent->kobj, class_name);
716 kfree(class_name); 752 kfree(class_name);
717 } 753 }
718#endif
719 sysfs_remove_link(&dev->kobj, "device"); 754 sysfs_remove_link(&dev->kobj, "device");
720 } 755 }
756
721 if (dev->kobj.parent != &dev->class->subsys.kobj) 757 if (dev->kobj.parent != &dev->class->subsys.kobj)
722 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); 758 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
759#else
760 if (dev->parent)
761 sysfs_remove_link(&dev->kobj, "device");
762
763 sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id);
764#endif
765
723 sysfs_remove_link(&dev->kobj, "subsystem"); 766 sysfs_remove_link(&dev->kobj, "subsystem");
724} 767}
725 768
@@ -830,26 +873,6 @@ int device_add(struct device *dev)
830 SymlinkError: 873 SymlinkError:
831 if (MAJOR(dev->devt)) 874 if (MAJOR(dev->devt))
832 device_remove_file(dev, &devt_attr); 875 device_remove_file(dev, &devt_attr);
833
834 if (dev->class) {
835 sysfs_remove_link(&dev->kobj, "subsystem");
836 /* If this is not a "fake" compatible device, remove the
837 * symlink from the class to the device. */
838 if (dev->kobj.parent != &dev->class->subsys.kobj)
839 sysfs_remove_link(&dev->class->subsys.kobj,
840 dev->bus_id);
841 if (parent) {
842#ifdef CONFIG_SYSFS_DEPRECATED
843 char *class_name = make_class_name(dev->class->name,
844 &dev->kobj);
845 if (class_name)
846 sysfs_remove_link(&dev->parent->kobj,
847 class_name);
848 kfree(class_name);
849#endif
850 sysfs_remove_link(&dev->kobj, "device");
851 }
852 }
853 ueventattrError: 876 ueventattrError:
854 device_remove_file(dev, &uevent_attr); 877 device_remove_file(dev, &uevent_attr);
855 attrError: 878 attrError:
@@ -932,23 +955,7 @@ void device_del(struct device * dev)
932 if (MAJOR(dev->devt)) 955 if (MAJOR(dev->devt))
933 device_remove_file(dev, &devt_attr); 956 device_remove_file(dev, &devt_attr);
934 if (dev->class) { 957 if (dev->class) {
935 sysfs_remove_link(&dev->kobj, "subsystem"); 958 device_remove_class_symlinks(dev);
936 /* If this is not a "fake" compatible device, remove the
937 * symlink from the class to the device. */
938 if (dev->kobj.parent != &dev->class->subsys.kobj)
939 sysfs_remove_link(&dev->class->subsys.kobj,
940 dev->bus_id);
941 if (parent) {
942#ifdef CONFIG_SYSFS_DEPRECATED
943 char *class_name = make_class_name(dev->class->name,
944 &dev->kobj);
945 if (class_name)
946 sysfs_remove_link(&dev->parent->kobj,
947 class_name);
948 kfree(class_name);
949#endif
950 sysfs_remove_link(&dev->kobj, "device");
951 }
952 959
953 down(&dev->class->sem); 960 down(&dev->class->sem);
954 /* notify any interfaces that the device is now gone */ 961 /* notify any interfaces that the device is now gone */
@@ -958,31 +965,6 @@ void device_del(struct device * dev)
958 /* remove the device from the class list */ 965 /* remove the device from the class list */
959 list_del_init(&dev->node); 966 list_del_init(&dev->node);
960 up(&dev->class->sem); 967 up(&dev->class->sem);
961
962 /* If we live in a parent class-directory, unreference it */
963 if (dev->kobj.parent->kset == &dev->class->class_dirs) {
964 struct device *d;
965 int other = 0;
966
967 /*
968 * if we are the last child of our class, delete
969 * our class-directory at this parent
970 */
971 down(&dev->class->sem);
972 list_for_each_entry(d, &dev->class->devices, node) {
973 if (d == dev)
974 continue;
975 if (d->kobj.parent == dev->kobj.parent) {
976 other = 1;
977 break;
978 }
979 }
980 if (!other)
981 kobject_del(dev->kobj.parent);
982
983 kobject_put(dev->kobj.parent);
984 up(&dev->class->sem);
985 }
986 } 968 }
987 device_remove_file(dev, &uevent_attr); 969 device_remove_file(dev, &uevent_attr);
988 device_remove_attrs(dev); 970 device_remove_attrs(dev);
@@ -1004,9 +986,9 @@ void device_del(struct device * dev)
1004 blocking_notifier_call_chain(&dev->bus->p->bus_notifier, 986 blocking_notifier_call_chain(&dev->bus->p->bus_notifier,
1005 BUS_NOTIFY_DEL_DEVICE, dev); 987 BUS_NOTIFY_DEL_DEVICE, dev);
1006 kobject_uevent(&dev->kobj, KOBJ_REMOVE); 988 kobject_uevent(&dev->kobj, KOBJ_REMOVE);
989 cleanup_device_parent(dev);
1007 kobject_del(&dev->kobj); 990 kobject_del(&dev->kobj);
1008 if (parent) 991 put_device(parent);
1009 put_device(parent);
1010} 992}
1011 993
1012/** 994/**