From 1350770112bd9bd5696cb52deb712370012d80e0 Mon Sep 17 00:00:00 2001 From: Martin Stoilov Date: Mon, 5 Feb 2007 16:15:23 -0800 Subject: kobject: kobj->k_name verification fix The function 'kobject_add' tries to verify the name of a new kobject instance is properly set before continuing. if (!kobj->k_name) kobj->k_name = kobj->name; if (!kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; } The statement: if (!kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; } is useless the way it is right now, because it can never be true. I think the code was intended to be: if (!kobj->k_name) kobj->k_name = kobj->name; if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; } because this would make sure the kobj->name buffer has something in it. So the missing '*' is just a typo. Although, I would much prefer expression like: if (*kobj->k_name == '\0') { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; } because this would've made the intention clear, in this patch I just restore the missing '*' without changing the coding style of the function. Signed-off-by: Martin Stoilov Signed-off-by: Andrew Morton Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index 2782f49e906e..93685f43bb9b 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -171,7 +171,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) return -ENOENT; if (!kobj->k_name) kobj->k_name = kobj->name; - if (!kobj->k_name) { + if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); return -EINVAL; -- cgit From f95d882d81ee731be2a4a3b34f86810e29b68836 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 10 Feb 2007 14:41:56 -0800 Subject: PCI/sysfs/kobject kernel-doc fixes Fix kernel-doc warnings in PCI, sysfs, and kobject files. Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/pci/pci-driver.c | 1 + drivers/pci/pci.c | 2 +- fs/sysfs/file.c | 2 +- lib/kobject.c | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) (limited to 'lib/kobject.c') diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 4438ae1ede4f..a3c1755b2f28 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -415,6 +415,7 @@ static struct kobj_type pci_driver_kobj_type = { * __pci_register_driver - register a new pci driver * @drv: the driver structure to register * @owner: owner module of drv + * @mod_name: module name string * * Adds the driver structure to the list of registered drivers. * Returns a negative value on error, otherwise 0. diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 8b44cff2c176..a7b869e24650 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1300,7 +1300,7 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) /** * pci_select_bars - Make BAR mask from the type of resource - * @pdev: the PCI device for which BAR mask is made + * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected * * This helper routine makes bar mask from the type of resource. diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c index c0e117649a4d..98b0910ad80c 100644 --- a/fs/sysfs/file.c +++ b/fs/sysfs/file.c @@ -54,7 +54,7 @@ static struct sysfs_ops subsys_sysfs_ops = { /** * add_to_collection - add buffer to a collection * @buffer: buffer to be added - * @node inode of set to add to + * @node: inode of set to add to */ static inline void diff --git a/lib/kobject.c b/lib/kobject.c index 2782f49e906e..4572809d1b95 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -326,6 +326,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name) /** * kobject_rename - change the name of an object * @kobj: object in question. + * @new_parent: object's new parent * @new_name: object's new name */ -- cgit From 9e993efb0da827634778554070f3c3ec4bdade33 Mon Sep 17 00:00:00 2001 From: Dmitriy Monakhov Date: Sat, 3 Mar 2007 16:11:21 +0300 Subject: kobject: new_device->kref wasn't putted after error in kobject_move() If error happen we jump to "out" label, in this case new_device not yet became the parent but it wasn't putted. Signed-off-by: Monakhov Dmitriy Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index f4f6176dcd12..057921c5945a 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -385,9 +385,11 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent) goto out; old_parent = kobj->parent; kobj->parent = new_parent; + new_parent = NULL; kobject_put(old_parent); kobject_uevent_env(kobj, KOBJ_MOVE, envp); out: + kobject_put(new_parent); kobject_put(kobj); kfree(devpath_string); kfree(devpath); -- cgit From 864062457a2e444227bd368ca5f2a2b740de604f Mon Sep 17 00:00:00 2001 From: Kay Sievers Date: Wed, 14 Mar 2007 03:25:56 +0100 Subject: 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 Signed-off-by: Greg Kroah-Hartman --- drivers/base/class.c | 2 +- drivers/base/core.c | 82 +++++++++++++++++++++++++++++++++++++++---------- include/linux/device.h | 3 +- include/linux/kobject.h | 2 ++ lib/kobject.c | 12 ++++++-- lib/kobject_uevent.c | 16 ++++++---- 6 files changed, 89 insertions(+), 28 deletions(-) (limited to 'lib/kobject.c') 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) INIT_LIST_HEAD(&cls->children); INIT_LIST_HEAD(&cls->devices); INIT_LIST_HEAD(&cls->interfaces); + kset_init(&cls->class_dirs); init_MUTEX(&cls->sem); error = kobject_set_name(&cls->subsys.kset.kobj, "%s", cls->name); if (error) @@ -163,7 +164,6 @@ int class_register(struct class * cls) void class_unregister(struct class * cls) { pr_debug("device class '%s': unregistering\n", cls->name); - kobject_unregister(cls->virtual_dir); remove_class_attrs(cls); subsystem_unregister(&cls->subsys); } 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, return NULL; } #else -static struct kobject * virtual_device_parent(struct device *dev) +static struct kobject *virtual_device_parent(struct device *dev) { - if (!dev->class) - return ERR_PTR(-ENODEV); - - if (!dev->class->virtual_dir) { - static struct kobject *virtual_dir = NULL; + static struct kobject *virtual_dir = NULL; - if (!virtual_dir) - virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); - dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name); - } + if (!virtual_dir) + virtual_dir = kobject_add_dir(&devices_subsys.kset.kobj, "virtual"); - return dev->class->virtual_dir; + return virtual_dir; } static struct kobject * get_device_parent(struct device *dev, struct device *parent) { - /* if this is a class device, and has no parent, create one */ - if ((dev->class) && (parent == NULL)) { - return virtual_device_parent(dev); - } else if (parent) + if (dev->class) { + struct kobject *kobj = NULL; + struct kobject *parent_kobj; + struct kobject *k; + + /* + * If we have no parent, we live in "virtual". + * Class-devices with a bus-device as parent, live + * in a class-directory to prevent namespace collisions. + */ + if (parent == NULL) + parent_kobj = virtual_device_parent(dev); + else if (parent->class) + return &parent->kobj; + else + parent_kobj = &parent->kobj; + + /* find our class-directory at the parent and reference it */ + spin_lock(&dev->class->class_dirs.list_lock); + list_for_each_entry(k, &dev->class->class_dirs.list, entry) + if (k->parent == parent_kobj) { + kobj = kobject_get(k); + break; + } + spin_unlock(&dev->class->class_dirs.list_lock); + if (kobj) + return kobj; + + /* or create a new class-directory at the parent device */ + return kobject_kset_add_dir(&dev->class->class_dirs, + parent_kobj, dev->class->name); + } + + if (parent) return &parent->kobj; return NULL; } - #endif + static int setup_parent(struct device *dev, struct device *parent) { struct kobject *kobj; @@ -541,7 +565,6 @@ int device_add(struct device *dev) pr_debug("DEV: registering device: ID = '%s'\n", dev->bus_id); parent = get_device(dev->parent); - error = setup_parent(dev, parent); if (error) goto Error; @@ -787,6 +810,31 @@ void device_del(struct device * dev) /* remove the device from the class list */ list_del_init(&dev->node); up(&dev->class->sem); + + /* If we live in a parent class-directory, unreference it */ + if (dev->kobj.parent->kset == &dev->class->class_dirs) { + struct device *d; + int other = 0; + + /* + * if we are the last child of our class, delete + * our class-directory at this parent + */ + down(&dev->class->sem); + list_for_each_entry(d, &dev->class->devices, node) { + if (d == dev) + continue; + if (d->kobj.parent == dev->kobj.parent) { + other = 1; + break; + } + } + if (!other) + kobject_del(dev->kobj.parent); + + kobject_put(dev->kobj.parent); + up(&dev->class->sem); + } } device_remove_file(dev, &dev->uevent_attr); 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 { struct list_head children; struct list_head devices; struct list_head interfaces; + struct kset class_dirs; struct semaphore sem; /* locks both the children and interfaces lists */ - struct kobject *virtual_dir; - struct class_attribute * class_attrs; struct class_device_attribute * class_dev_attrs; 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 *); extern struct kobject * kobject_get(struct kobject *); extern void kobject_put(struct kobject *); +extern struct kobject *kobject_kset_add_dir(struct kset *kset, + struct kobject *, const char *); extern struct kobject *kobject_add_dir(struct kobject *, const char *); extern 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 = { }; /** - * kobject_add_dir - add sub directory of object. + * kobject__kset_add_dir - add sub directory of object. + * @kset: kset the directory is belongs to. * @parent: object in which a directory is created. * @name: directory name. * * Add a plain directory object as child of given object. */ -struct kobject *kobject_add_dir(struct kobject *parent, const char *name) +struct kobject *kobject_kset_add_dir(struct kset *kset, + struct kobject *parent, const char *name) { struct kobject *k; int ret; @@ -506,6 +508,7 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name) if (!k) return NULL; + k->kset = kset; k->parent = parent; k->ktype = &dir_ktype; kobject_set_name(k, name); @@ -520,6 +523,11 @@ struct kobject *kobject_add_dir(struct kobject *parent, const char *name) return k; } +struct kobject *kobject_add_dir(struct kobject *parent, const char *name) +{ + return kobject_kset_add_dir(NULL, parent, name); +} + /** * kset_init - initialize a kset for use * @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, return 0; } + /* originating subsystem */ + if (uevent_ops && uevent_ops->name) + subsystem = uevent_ops->name(kset, kobj); + else + subsystem = kobject_name(&kset->kobj); + if (!subsystem) { + pr_debug("unset subsytem caused the event to drop!\n"); + return 0; + } + /* environment index */ envp = kzalloc(NUM_ENVP * sizeof (char *), GFP_KERNEL); if (!envp) @@ -134,12 +144,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, goto exit; } - /* originating subsystem */ - if (uevent_ops && uevent_ops->name) - subsystem = uevent_ops->name(kset, kobj); - else - subsystem = kobject_name(&kset->kobj); - /* event environemnt for helper process only */ envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; -- cgit From 460f7e9a1bde2c74f060f7ce0a308dab4be6a56b Mon Sep 17 00:00:00 2001 From: Dmitriy Monakhov Date: Sat, 10 Mar 2007 14:00:10 +0300 Subject: kobject: kobject_shadow_add cleanup - correct function name in comments - parrent assignment does metter only inside "if" block, so move it inside this block. Signed-off-by: Monakhov Dmitriy Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index f66455155606..bbbfab4145e6 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -157,7 +157,7 @@ static void unlink(struct kobject * kobj) } /** - * kobject_add - add an object to the hierarchy. + * kobject_shadow_add - add an object to the hierarchy. * @kobj: object. * @shadow_parent: sysfs directory to add to. */ @@ -190,8 +190,8 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) list_add_tail(&kobj->entry,&kobj->kset->list); spin_unlock(&kobj->kset->list_lock); + kobj->parent = parent; } - kobj->parent = parent; error = create_dir(kobj, shadow_parent); if (error) { -- cgit From ca2f37dbc5324c7278577731033a358f1f86050a Mon Sep 17 00:00:00 2001 From: Jean Tourrilhes Date: Wed, 7 Mar 2007 10:49:30 -0800 Subject: Driver core: notify userspace of network device renames Provide rename event for when we rename network devices. Signed-off-by: Jean Tourrilhes Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 30 ++++++++++++++++++++++++++++++ net/core/net-sysfs.c | 11 +++++++++++ 2 files changed, 41 insertions(+) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index bbbfab4145e6..db1d23707eb1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -311,13 +311,43 @@ EXPORT_SYMBOL(kobject_set_name); int kobject_rename(struct kobject * kobj, const char *new_name) { int error = 0; + const char *devpath = NULL; + char *devpath_string = NULL; + char *envp[2]; kobj = kobject_get(kobj); if (!kobj) return -EINVAL; if (!kobj->parent) return -EINVAL; + + devpath = kobject_get_path(kobj, GFP_KERNEL); + if (!devpath) { + error = -ENOMEM; + goto out; + } + devpath_string = kmalloc(strlen(devpath) + 15, GFP_KERNEL); + if (!devpath_string) { + error = -ENOMEM; + goto out; + } + sprintf(devpath_string, "DEVPATH_OLD=%s", devpath); + envp[0] = devpath_string; + envp[1] = NULL; + /* Note : if we want to send the new name alone, not the full path, + * we could probably use kobject_name(kobj); */ + error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name); + + /* This function is mostly/only used for network interface. + * Some hotplug package track interfaces by their name and + * therefore want to know when the name is changed by the user. */ + if (!error) + kobject_uevent_env(kobj, KOBJ_MOVE, envp); + +out: + kfree(devpath_string); + kfree(devpath); kobject_put(kobj); return error; diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 221a64ab64f7..e441ec7988c1 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -421,6 +421,17 @@ static int netdev_uevent(struct device *d, char **envp, buf += n; size -= n; + if ((size <= 0) || (i >= num_envp)) + return -ENOMEM; + + /* pass ifindex to uevent. + * ifindex is useful as it won't change (interface name may change) + * and is what RtNetlink uses natively. */ + envp[i++] = buf; + n = snprintf(buf, size, "IFINDEX=%d", dev->ifindex) + 1; + buf += n; + size -= n; + if ((size <= 0) || (i >= num_envp)) return -ENOMEM; -- cgit From 88db4721d47bc59b92d46de04e21c7975ea983f2 Mon Sep 17 00:00:00 2001 From: Cornelia Huck Date: Tue, 10 Apr 2007 14:35:27 +0200 Subject: kobject: kobject_add() reference leak We leak a reference if we attempt to add a kobject with no name. Signed-off-by: Cornelia Huck Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index db1d23707eb1..eb251aae78dd 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -174,6 +174,7 @@ int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent) if (!*kobj->k_name) { pr_debug("kobject attempted to be registered with no name!\n"); WARN_ON(1); + kobject_put(kobj); return -EINVAL; } parent = kobject_get(kobj->parent); -- cgit From 4628803062d93dadc6ba8e801fd075526904a38c Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 9 Apr 2007 11:52:31 -0400 Subject: kobject core: remove rwsem from struct subsystem It isn't used at all by the driver core anymore, and the few usages of it within the kernel have now all been fixed as most of them were using it incorrectly. So remove it. Now the whole struct subsys can be removed from the system, but that's for a later patch... Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- include/linux/kobject.h | 2 -- lib/kobject.c | 4 +--- 2 files changed, 1 insertion(+), 5 deletions(-) (limited to 'lib/kobject.c') diff --git a/include/linux/kobject.h b/include/linux/kobject.h index d37cd7f10e3d..a659a97eccf1 100644 --- a/include/linux/kobject.h +++ b/include/linux/kobject.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -177,7 +176,6 @@ extern struct kobject * kset_find_obj(struct kset *, const char *); struct subsystem { struct kset kset; - struct rw_semaphore rwsem; }; #define decl_subsys(_name,_type,_uevent_ops) \ diff --git a/lib/kobject.c b/lib/kobject.c index eb251aae78dd..2882aff6f3d1 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -652,7 +652,6 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) void subsystem_init(struct subsystem * s) { - init_rwsem(&s->rwsem); kset_init(&s->kset); } @@ -661,8 +660,7 @@ void subsystem_init(struct subsystem * s) * @s: the subsystem we're registering. * * Once we register the subsystem, we want to make sure that - * the kset points back to this subsystem for correct usage of - * the rwsem. + * the kset points back to this subsystem. */ int subsystem_register(struct subsystem * s) -- cgit From 2753133eb3321feb81dcb9c88141dd2aa5973ee1 Mon Sep 17 00:00:00 2001 From: "Eric W. Biederman" Date: Fri, 6 Apr 2007 10:47:11 -0600 Subject: kobject: Comment and warning fixes to kobject.c This dots some i's and crosses some t's after left over from when kobject_kset_add_dir was built from kobject_add_dir. Signed-off-by: Eric W. Biederman Cc: Kay Sievers Signed-off-by: Greg Kroah-Hartman --- lib/kobject.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'lib/kobject.c') diff --git a/lib/kobject.c b/lib/kobject.c index 2882aff6f3d1..cecf2fbede3e 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -519,7 +519,7 @@ static struct kobj_type dir_ktype = { }; /** - * kobject__kset_add_dir - add sub directory of object. + * kobject_kset_add_dir - add sub directory of object. * @kset: kset the directory is belongs to. * @parent: object in which a directory is created. * @name: directory name. @@ -545,8 +545,8 @@ struct kobject *kobject_kset_add_dir(struct kset *kset, kobject_set_name(k, name); ret = kobject_register(k); if (ret < 0) { - printk(KERN_WARNING "kobject_add_dir: " - "kobject_register error: %d\n", ret); + printk(KERN_WARNING "%s: kobject_register error: %d\n", + __func__, ret); kobject_del(k); return NULL; } @@ -554,6 +554,13 @@ struct kobject *kobject_kset_add_dir(struct kset *kset, return k; } +/** + * kobject_add_dir - add sub directory of object. + * @parent: object in which a directory is created. + * @name: directory name. + * + * Add a plain directory object as child of given object. + */ struct kobject *kobject_add_dir(struct kobject *parent, const char *name) { return kobject_kset_add_dir(NULL, parent, name); -- cgit