aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKay Sievers <kay.sievers@vrfy.org>2007-03-13 22:25:56 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2007-04-27 13:57:28 -0400
commit864062457a2e444227bd368ca5f2a2b740de604f (patch)
tree38e516852ee9825b5ffe0b1f2e8abea0a88b1674
parent00ed8e3dda47f8421b11da17e353d7db8c878121 (diff)
driver core: fix namespace issue with devices assigned to classes
- uses a kset in "struct class" to keep track of all directories belonging to this class - merges with the /sys/devices/virtual logic. - removes the namespace-dir if the last member of that class leaves the directory. There may be locking or refcounting fixes left, I stopped when it seemed to work with network and sound modules. :) From: Kay Sievers <kay.sievers@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/base/class.c2
-rw-r--r--drivers/base/core.c82
-rw-r--r--include/linux/device.h3
-rw-r--r--include/linux/kobject.h2
-rw-r--r--lib/kobject.c12
-rw-r--r--lib/kobject_uevent.c16
6 files changed, 89 insertions, 28 deletions
diff --git a/drivers/base/class.c b/drivers/base/class.c
index d5968128be2b..80bbb2074636 100644
--- a/drivers/base/class.c
+++ b/drivers/base/class.c
@@ -145,6 +145,7 @@ int class_register(struct class * cls)
145 INIT_LIST_HEAD(&cls->children); 145 INIT_LIST_HEAD(&cls->children);
146 INIT_LIST_HEAD(&cls->devices); 146 INIT_LIST_HEAD(&cls->devices);
147 INIT_LIST_HEAD(&cls->interfaces); 147 INIT_LIST_HEAD(&cls->interfaces);
148 kset_init(&cls->class_dirs);
148 init_MUTEX(&cls->sem); 149 init_MUTEX(&cls->sem);
149 error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); 150 error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name);
150 if (error) 151 if (error)
@@ -163,7 +164,6 @@ int class_register(struct class * cls)
163void class_unregister(struct class * cls) 164void class_unregister(struct class * cls)
164{ 165{
165 pr_debug("device class '%s': unregistering\n", cls->name); 166 pr_debug("device class '%s': unregistering\n", cls->name);
166 kobject_unregister(cls->virtual_dir);
167 remove_class_attrs(cls); 167 remove_class_attrs(cls);
168 subsystem_unregister(&cls->subsys); 168 subsystem_unregister(&cls->subsys);
169} 169}
diff --git a/drivers/base/core.c b/drivers/base/core.c
index db3a151be4a1..658eae5dacda 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -477,34 +477,58 @@ static struct kobject * get_device_parent(struct device *dev,
477 return NULL; 477 return NULL;
478} 478}
479#else 479#else
480static struct kobject * virtual_device_parent(struct device *dev) 480static struct kobject *virtual_device_parent(struct device *dev)
481{ 481{
482 if (!dev->class) 482 static struct kobject *virtual_dir = NULL;
483 return ERR_PTR(-ENODEV);
484
485 if (!dev->class->virtual_dir) {
486 static struct kobject *virtual_dir = NULL;
487 483
488 if (!virtual_dir) 484 if (!virtual_dir)
489 virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); 485 virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual");
490 dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
491 }
492 486
493 return dev->class->virtual_dir; 487 return virtual_dir;
494} 488}
495 489
496static struct kobject * get_device_parent(struct device *dev, 490static struct kobject * get_device_parent(struct device *dev,
497 struct device *parent) 491 struct device *parent)
498{ 492{
499 /* if this is a class device, and has no parent, create one */ 493 if (dev->class) {
500 if ((dev->class) && (parent == NULL)) { 494 struct kobject *kobj = NULL;
501 return virtual_device_parent(dev); 495 struct kobject *parent_kobj;
502 } else if (parent) 496 struct kobject *k;
497
498 /*
499 * If we have no parent, we live in "virtual".
500 * Class-devices with a bus-device as parent, live
501 * in a class-directory to prevent namespace collisions.
502 */
503 if (parent == NULL)
504 parent_kobj = virtual_device_parent(dev);
505 else if (parent->class)
506 return &parent->kobj;
507 else
508 parent_kobj = &parent->kobj;
509
510 /* find our class-directory at the parent and reference it */
511 spin_lock(&dev->class->class_dirs.list_lock);
512 list_for_each_entry(k, &dev->class->class_dirs.list, entry)
513 if (k->parent == parent_kobj) {
514 kobj = kobject_get(k);
515 break;
516 }
517 spin_unlock(&dev->class->class_dirs.list_lock);
518 if (kobj)
519 return kobj;
520
521 /* or create a new class-directory at the parent device */
522 return kobject_kset_add_dir(&dev->class->class_dirs,
523 parent_kobj, dev->class->name);
524 }
525
526 if (parent)
503 return &parent->kobj; 527 return &parent->kobj;
504 return NULL; 528 return NULL;
505} 529}
506
507#endif 530#endif
531
508static int setup_parent(struct device *dev, struct device *parent) 532static int setup_parent(struct device *dev, struct device *parent)
509{ 533{
510 struct kobject *kobj; 534 struct kobject *kobj;
@@ -541,7 +565,6 @@ int device_add(struct device *dev)
541 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); 565 pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id);
542 566
543 parent = get_device(dev->parent); 567 parent = get_device(dev->parent);
544
545 error = setup_parent(dev, parent); 568 error = setup_parent(dev, parent);
546 if (error) 569 if (error)
547 goto Error; 570 goto Error;
@@ -787,6 +810,31 @@ void device_del(struct device * dev)
787 /* remove the device from the class list */ 810 /* remove the device from the class list */
788 list_del_init(&dev->node); 811 list_del_init(&dev->node);
789 up(&dev->class->sem); 812 up(&dev->class->sem);
813
814 /* If we live in a parent class-directory, unreference it */
815 if (dev->kobj.parent->kset == &dev->class->class_dirs) {
816 struct device *d;
817 int other = 0;
818
819 /*
820 * if we are the last child of our class, delete
821 * our class-directory at this parent
822 */
823 down(&dev->class->sem);
824 list_for_each_entry(d, &dev->class->devices, node) {
825 if (d == dev)
826 continue;
827 if (d->kobj.parent == dev->kobj.parent) {
828 other = 1;
829 break;
830 }
831 }
832 if (!other)
833 kobject_del(dev->kobj.parent);
834
835 kobject_put(dev->kobj.parent);
836 up(&dev->class->sem);
837 }
790 } 838 }
791 device_remove_file(dev, &dev->uevent_attr); 839 device_remove_file(dev, &dev->uevent_attr);
792 device_remove_groups(dev); 840 device_remove_groups(dev);
diff --git a/include/linux/device.h b/include/linux/device.h
index 5cf30e95c8b6..de0e73eae6bc 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -181,10 +181,9 @@ struct class {
181 struct list_head children; 181 struct list_head children;
182 struct list_head devices; 182 struct list_head devices;
183 struct list_head interfaces; 183 struct list_head interfaces;
184 struct kset class_dirs;
184 struct semaphore sem; /* locks both the children and interfaces lists */ 185 struct semaphore sem; /* locks both the children and interfaces lists */
185 186
186 struct kobject *virtual_dir;
187
188 struct class_attribute * class_attrs; 187 struct class_attribute * class_attrs;
189 struct class_device_attribute * class_dev_attrs; 188 struct class_device_attribute * class_dev_attrs;
190 struct device_attribute * dev_attrs; 189 struct device_attribute * dev_attrs;
diff --git a/include/linux/kobject.h b/include/linux/kobject.h
index b850e0310538..d37cd7f10e3d 100644
--- a/include/linux/kobject.h
+++ b/include/linux/kobject.h
@@ -89,6 +89,8 @@ extern void kobject_unregister(struct kobject *);
89extern struct kobject * kobject_get(struct kobject *); 89extern struct kobject * kobject_get(struct kobject *);
90extern void kobject_put(struct kobject *); 90extern void kobject_put(struct kobject *);
91 91
92extern struct kobject *kobject_kset_add_dir(struct kset *kset,
93 struct kobject *, const char *);
92extern struct kobject *kobject_add_dir(struct kobject *, const char *); 94extern struct kobject *kobject_add_dir(struct kobject *, const char *);
93 95
94extern char * kobject_get_path(struct kobject *, gfp_t); 96extern char * kobject_get_path(struct kobject *, gfp_t);
diff --git a/lib/kobject.c b/lib/kobject.c
index 057921c5945a..f66455155606 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -488,13 +488,15 @@ static struct kobj_type dir_ktype = {
488}; 488};
489 489
490/** 490/**
491 * kobject_add_dir - add sub directory of object. 491 * kobject__kset_add_dir - add sub directory of object.
492 * @kset: kset the directory is belongs to.
492 * @parent: object in which a directory is created. 493 * @parent: object in which a directory is created.
493 * @name: directory name. 494 * @name: directory name.
494 * 495 *
495 * Add a plain directory object as child of given object. 496 * Add a plain directory object as child of given object.
496 */ 497 */
497struct kobject *kobject_add_dir(struct kobject *parent, const char *name) 498struct kobject *kobject_kset_add_dir(struct kset *kset,
499 struct kobject *parent, const char *name)
498{ 500{
499 struct kobject *k; 501 struct kobject *k;
500 int ret; 502 int ret;
@@ -506,6 +508,7 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
506 if (!k) 508 if (!k)
507 return NULL; 509 return NULL;
508 510
511 k->kset = kset;
509 k->parent = parent; 512 k->parent = parent;
510 k->ktype = &dir_ktype; 513 k->ktype = &dir_ktype;
511 kobject_set_name(k, name); 514 kobject_set_name(k, name);
@@ -520,6 +523,11 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
520 return k; 523 return k;
521} 524}
522 525
526struct kobject *kobject_add_dir(struct kobject *parent, const char *name)
527{
528 return kobject_kset_add_dir(NULL, parent, name);
529}
530
523/** 531/**
524 * kset_init - initialize a kset for use 532 * kset_init - initialize a kset for use
525 * @k: kset 533 * @k: kset
diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c
index 82fc1794b691..4122f38330d4 100644
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -115,6 +115,16 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
115 return 0; 115 return 0;
116 } 116 }
117 117
118 /* originating subsystem */
119 if (uevent_ops && uevent_ops->name)
120 subsystem = uevent_ops->name(kset, kobj);
121 else
122 subsystem = kobject_name(&kset->kobj);
123 if (!subsystem) {
124 pr_debug("unset subsytem caused the event to drop!\n");
125 return 0;
126 }
127
118 /* environment index */ 128 /* environment index */
119 envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); 129 envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL);
120 if (!envp) 130 if (!envp)
@@ -134,12 +144,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action,
134 goto exit; 144 goto exit;
135 } 145 }
136 146
137 /* originating subsystem */
138 if (uevent_ops && uevent_ops->name)
139 subsystem = uevent_ops->name(kset, kobj);
140 else
141 subsystem = kobject_name(&kset->kobj);
142
143 /* event environemnt for helper process only */ 147 /* event environemnt for helper process only */
144 envp[i++] = "HOME=/"; 148 envp[i++] = "HOME=/";
145 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; 149 envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";