X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=lib%2Fkobject.c;h=f07c57252e823278f6dd50b8ca84eb8e747f597f;hb=70764a905785ebacc8d44fed7a12fba3db267ae6;hp=4d52b6f534bcbb44122d6bf946632acfd93c0ed0;hpb=cfb36fff45e3997b8044c81045fc4869ba5f281a;p=safe%2Fjmp%2Flinux-2.6 diff --git a/lib/kobject.c b/lib/kobject.c index 4d52b6f..f07c572 100644 --- a/lib/kobject.c +++ b/lib/kobject.c @@ -18,58 +18,52 @@ #include #include -/** - * populate_dir - populate directory with attributes. - * @kobj: object we're working on. - * - * Most subsystems have a set of default attributes that - * are associated with an object that registers with them. - * This is a helper called during object registration that - * loops through the default attributes of the subsystem - * and creates attributes files for them in sysfs. +/* + * populate_dir - populate directory with attributes. + * @kobj: object we're working on. * + * Most subsystems have a set of default attributes that are associated + * with an object that registers with them. This is a helper called during + * object registration that loops through the default attributes of the + * subsystem and creates attributes files for them in sysfs. */ - -static int populate_dir(struct kobject * kobj) +static int populate_dir(struct kobject *kobj) { - struct kobj_type * t = get_ktype(kobj); - struct attribute * attr; + struct kobj_type *t = get_ktype(kobj); + struct attribute *attr; int error = 0; int i; - + if (t && t->default_attrs) { for (i = 0; (attr = t->default_attrs[i]) != NULL; i++) { - if ((error = sysfs_create_file(kobj,attr))) + error = sysfs_create_file(kobj, attr); + if (error) break; } } return error; } -static int create_dir(struct kobject * kobj) +static int create_dir(struct kobject *kobj) { int error = 0; if (kobject_name(kobj)) { error = sysfs_create_dir(kobj); if (!error) { - if ((error = populate_dir(kobj))) + error = populate_dir(kobj); + if (error) sysfs_remove_dir(kobj); } } return error; } -static inline struct kobject * to_kobj(struct list_head * entry) -{ - return container_of(entry,struct kobject,entry); -} - static int get_kobj_path_length(struct kobject *kobj) { int length = 1; - struct kobject * parent = kobj; + struct kobject *parent = kobj; - /* walk up the ancestors until we hit the one pointing to the + /* walk up the ancestors until we hit the one pointing to the * root. * Add 1 to strlen for leading '/' of each level. */ @@ -84,18 +78,19 @@ static int get_kobj_path_length(struct kobject *kobj) static void fill_kobj_path(struct kobject *kobj, char *path, int length) { - struct kobject * parent; + struct kobject *parent; --length; for (parent = kobj; parent; parent = parent->parent) { int cur = strlen(kobject_name(parent)); /* back up enough to print this name with '/' */ length -= cur; - strncpy (path + length, kobject_name(parent), cur); + strncpy(path + length, kobject_name(parent), cur); *(path + --length) = '/'; } - pr_debug("%s: path = '%s'\n",__FUNCTION__,path); + pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj), + kobj, __func__, path); } /** @@ -123,147 +118,118 @@ char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask) } EXPORT_SYMBOL_GPL(kobject_get_path); -/** - * kobject_init - initialize object. - * @kobj: object in question. - */ -void kobject_init(struct kobject * kobj) +/* add the kobject to its kset's list */ +static void kobj_kset_join(struct kobject *kobj) { - if (!kobj) + if (!kobj->kset) return; - kref_init(&kobj->kref); - INIT_LIST_HEAD(&kobj->entry); + + kset_get(kobj->kset); + spin_lock(&kobj->kset->list_lock); + list_add_tail(&kobj->entry, &kobj->kset->list); + spin_unlock(&kobj->kset->list_lock); } +/* remove the kobject from its kset's list */ +static void kobj_kset_leave(struct kobject *kobj) +{ + if (!kobj->kset) + return; -/** - * unlink - remove kobject from kset list. - * @kobj: kobject. - * - * Remove the kobject from the kset list and decrement - * its parent's refcount. - * This is separated out, so we can use it in both - * kobject_del() and kobject_add() on error. - */ + spin_lock(&kobj->kset->list_lock); + list_del_init(&kobj->entry); + spin_unlock(&kobj->kset->list_lock); + kset_put(kobj->kset); +} -static void unlink(struct kobject * kobj) +static void kobject_init_internal(struct kobject *kobj) { - if (kobj->kset) { - spin_lock(&kobj->kset->list_lock); - list_del_init(&kobj->entry); - spin_unlock(&kobj->kset->list_lock); - } - kobject_put(kobj); + if (!kobj) + return; + kref_init(&kobj->kref); + INIT_LIST_HEAD(&kobj->entry); + kobj->state_in_sysfs = 0; + kobj->state_add_uevent_sent = 0; + kobj->state_remove_uevent_sent = 0; + kobj->state_initialized = 1; } -/** - * kobject_add - add an object to the hierarchy. - * @kobj: object. - */ -int kobject_add(struct kobject * kobj) +static int kobject_add_internal(struct kobject *kobj) { int error = 0; - struct kobject * parent; + struct kobject *parent; - if (!(kobj = kobject_get(kobj))) + if (!kobj) return -ENOENT; - if (!kobj->k_name) - kobject_set_name(kobj, "NO_NAME"); - if (!*kobj->k_name) { - pr_debug("kobject attempted to be registered with no name!\n"); - WARN_ON(1); - kobject_put(kobj); + + if (!kobj->name || !kobj->name[0]) { + WARN(1, "kobject: (%p): attempted to be registered with empty " + "name!\n", kobj); return -EINVAL; } - parent = kobject_get(kobj->parent); - pr_debug("kobject %s: registering. parent: %s, set: %s\n", - kobject_name(kobj), parent ? kobject_name(parent) : "", - kobj->kset ? kobject_name(&kobj->kset->kobj) : "" ); + parent = kobject_get(kobj->parent); + /* join kset if set, use it as parent if we do not already have one */ if (kobj->kset) { - kobj->kset = kset_get(kobj->kset); - - if (!parent) { + if (!parent) parent = kobject_get(&kobj->kset->kobj); - /* - * If the kset is our parent, get a second - * reference, we drop both the kset and the - * parent ref on cleanup - */ - kobject_get(parent); - } - - spin_lock(&kobj->kset->list_lock); - list_add_tail(&kobj->entry, &kobj->kset->list); - spin_unlock(&kobj->kset->list_lock); + kobj_kset_join(kobj); kobj->parent = parent; } + pr_debug("kobject: '%s' (%p): %s: parent: '%s', set: '%s'\n", + kobject_name(kobj), kobj, __func__, + parent ? kobject_name(parent) : "", + kobj->kset ? kobject_name(&kobj->kset->kobj) : ""); + error = create_dir(kobj); if (error) { - /* unlink does the kobject_put() for us */ - unlink(kobj); + kobj_kset_leave(kobj); kobject_put(parent); + kobj->parent = NULL; /* be noisy on error issues */ if (error == -EEXIST) - printk(KERN_ERR "kobject_add failed for %s with " + printk(KERN_ERR "%s failed for %s with " "-EEXIST, don't try to register things with " "the same name in the same directory.\n", - kobject_name(kobj)); + __func__, kobject_name(kobj)); else - printk(KERN_ERR "kobject_add failed for %s (%d)\n", - kobject_name(kobj), error); + printk(KERN_ERR "%s failed for %s (%d)\n", + __func__, kobject_name(kobj), error); dump_stack(); - } + } else + kobj->state_in_sysfs = 1; return error; } /** - * kobject_register - initialize and add an object. - * @kobj: object in question. - */ - -int kobject_register(struct kobject * kobj) -{ - int error = -EINVAL; - if (kobj) { - kobject_init(kobj); - error = kobject_add(kobj); - if (!error) - kobject_uevent(kobj, KOBJ_ADD); - } - return error; -} - -/** * kobject_set_name_vargs - Set the name of an kobject * @kobj: struct kobject to set the name of * @fmt: format string used to build the name * @vargs: vargs to format the string. */ -static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, +int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, va_list vargs) { - va_list aq; - char *name; + const char *old_name = kobj->name; + char *s; - va_copy(aq, vargs); - name = kvasprintf(GFP_KERNEL, fmt, vargs); - va_end(aq); + if (kobj->name && !fmt) + return 0; - if (!name) + kobj->name = kvasprintf(GFP_KERNEL, fmt, vargs); + if (!kobj->name) return -ENOMEM; - /* Free the old name, if necessary. */ - kfree(kobj->k_name); - - /* Now, set the new name */ - kobj->k_name = name; + /* ewww... some of these buggers have '/' in the name ... */ + while ((s = strchr(kobj->name, '/'))) + s[0] = '!'; + kfree(old_name); return 0; } @@ -278,19 +244,19 @@ static int kobject_set_name_vargs(struct kobject *kobj, const char *fmt, */ int kobject_set_name(struct kobject *kobj, const char *fmt, ...) { - va_list args; + va_list vargs; int retval; - va_start(args, fmt); - retval = kobject_set_name_vargs(kobj, fmt, args); - va_end(args); + va_start(vargs, fmt); + retval = kobject_set_name_vargs(kobj, fmt, vargs); + va_end(vargs); return retval; } EXPORT_SYMBOL(kobject_set_name); /** - * kobject_init_ng - initialize a kobject structure + * kobject_init - initialize a kobject structure * @kobj: pointer to the kobject to initialize * @ktype: pointer to the ktype for this kobject. * @@ -301,7 +267,7 @@ EXPORT_SYMBOL(kobject_set_name); * to kobject_put(), not by a call to kfree directly to ensure that all of * the memory is cleaned up properly. */ -void kobject_init_ng(struct kobject *kobj, struct kobj_type *ktype) +void kobject_init(struct kobject *kobj, struct kobj_type *ktype) { char *err_str; @@ -313,43 +279,39 @@ void kobject_init_ng(struct kobject *kobj, struct kobj_type *ktype) err_str = "must have a ktype to be initialized properly!\n"; goto error; } - if (atomic_read(&kobj->kref.refcount)) { + if (kobj->state_initialized) { /* do not error out as sometimes we can recover */ - printk(KERN_ERR "kobject: reference count is already set, " - "something is seriously wrong.\n"); + printk(KERN_ERR "kobject (%p): tried to init an initialized " + "object, something is seriously wrong.\n", kobj); dump_stack(); } - kref_init(&kobj->kref); - INIT_LIST_HEAD(&kobj->entry); + kobject_init_internal(kobj); kobj->ktype = ktype; return; error: - printk(KERN_ERR "kobject: %s\n", err_str); + printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str); dump_stack(); } -EXPORT_SYMBOL(kobject_init_ng); +EXPORT_SYMBOL(kobject_init); static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, const char *fmt, va_list vargs) { - va_list aq; int retval; - va_copy(aq, vargs); - retval = kobject_set_name_vargs(kobj, fmt, aq); - va_end(aq); + retval = kobject_set_name_vargs(kobj, fmt, vargs); if (retval) { printk(KERN_ERR "kobject: can not set name properly!\n"); return retval; } kobj->parent = parent; - return kobject_add(kobj); + return kobject_add_internal(kobj); } /** - * kobject_add_ng - the main kobject add function + * kobject_add - the main kobject add function * @kobj: the kobject to add * @parent: pointer to the parent of the kobject. * @fmt: format to name the kobject with. @@ -365,23 +327,16 @@ static int kobject_add_varg(struct kobject *kobj, struct kobject *parent, * * If this function returns an error, kobject_put() must be called to * properly clean up the memory associated with the object. - * - * If the function is successful, the only way to properly clean up the - * memory is with a call to kobject_del(), in which case, a call to - * kobject_put() is not necessary (kobject_del() does the final - * kobject_put() to call the release function in the ktype's release - * pointer.) - * * Under no instance should the kobject that is passed to this function * be directly freed with a call to kfree(), that can leak memory. * - * Note, no uevent will be created with this call, the caller should set + * Note, no "add" uevent will be created with this call, the caller should set * up all of the necessary sysfs files for the object and then call * kobject_uevent() with the UEVENT_ADD parameter to ensure that * userspace is properly notified of this kobject's creation. */ -int kobject_add_ng(struct kobject *kobj, struct kobject *parent, - const char *fmt, ...) +int kobject_add(struct kobject *kobj, struct kobject *parent, + const char *fmt, ...) { va_list args; int retval; @@ -389,13 +344,20 @@ int kobject_add_ng(struct kobject *kobj, struct kobject *parent, if (!kobj) return -EINVAL; + if (!kobj->state_initialized) { + printk(KERN_ERR "kobject '%s' (%p): tried to add an " + "uninitialized object, something is seriously wrong.\n", + kobject_name(kobj), kobj); + dump_stack(); + return -EINVAL; + } va_start(args, fmt); retval = kobject_add_varg(kobj, parent, fmt, args); va_end(args); return retval; } -EXPORT_SYMBOL(kobject_add_ng); +EXPORT_SYMBOL(kobject_add); /** * kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy @@ -404,9 +366,9 @@ EXPORT_SYMBOL(kobject_add_ng); * @parent: pointer to the parent of this kobject. * @fmt: the name of the kobject. * - * This function combines the call to kobject_init_ng() and - * kobject_add_ng(). The same type of error handling after a call to - * kobject_add_ng() and kobject lifetime rules are the same here. + * This function combines the call to kobject_init() and + * kobject_add(). The same type of error handling after a call to + * kobject_add() and kobject lifetime rules are the same here. */ int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, struct kobject *parent, const char *fmt, ...) @@ -414,7 +376,7 @@ int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, va_list args; int retval; - kobject_init_ng(kobj, ktype); + kobject_init(kobj, ktype); va_start(args, fmt); retval = kobject_add_varg(kobj, parent, fmt, args); @@ -425,15 +387,20 @@ int kobject_init_and_add(struct kobject *kobj, struct kobj_type *ktype, EXPORT_SYMBOL_GPL(kobject_init_and_add); /** - * kobject_rename - change the name of an object - * @kobj: object in question. - * @new_name: object's new name + * kobject_rename - change the name of an object + * @kobj: object in question. + * @new_name: object's new name + * + * It is the responsibility of the caller to provide mutual + * exclusion between two different calls of kobject_rename + * on the same kobject and to ensure that new_name is valid and + * won't conflict with other kobjects. */ - -int kobject_rename(struct kobject * kobj, const char *new_name) +int kobject_rename(struct kobject *kobj, const char *new_name) { int error = 0; const char *devpath = NULL; + const char *dup_name = NULL, *name; char *devpath_string = NULL; char *envp[2]; @@ -443,19 +410,6 @@ int kobject_rename(struct kobject * kobj, const char *new_name) if (!kobj->parent) return -EINVAL; - /* see if this name is already in use */ - if (kobj->kset) { - struct kobject *temp_kobj; - temp_kobj = kset_find_obj(kobj->kset, new_name); - if (temp_kobj) { - printk(KERN_WARNING "kobject '%s' cannot be renamed " - "to '%s' as '%s' is already in existence.\n", - kobject_name(kobj), new_name, new_name); - kobject_put(temp_kobj); - return -EINVAL; - } - } - devpath = kobject_get_path(kobj, GFP_KERNEL); if (!devpath) { error = -ENOMEM; @@ -470,28 +424,40 @@ int kobject_rename(struct kobject * kobj, const char *new_name) envp[0] = devpath_string; envp[1] = NULL; + name = dup_name = kstrdup(new_name, GFP_KERNEL); + if (!name) { + error = -ENOMEM; + goto out; + } + error = sysfs_rename_dir(kobj, new_name); + if (error) + goto out; + + /* Install the new kobject name */ + dup_name = kobj->name; + kobj->name = 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); + kobject_uevent_env(kobj, KOBJ_MOVE, envp); out: + kfree(dup_name); kfree(devpath_string); kfree(devpath); kobject_put(kobj); return error; } +EXPORT_SYMBOL_GPL(kobject_rename); /** - * kobject_move - move object to another parent - * @kobj: object in question. - * @new_parent: object's new parent (can be NULL) + * kobject_move - move object to another parent + * @kobj: object in question. + * @new_parent: object's new parent (can be NULL) */ - int kobject_move(struct kobject *kobj, struct kobject *new_parent) { int error; @@ -539,39 +505,26 @@ out: } /** - * kobject_del - unlink kobject from hierarchy. - * @kobj: object. + * kobject_del - unlink kobject from hierarchy. + * @kobj: object. */ - -void kobject_del(struct kobject * kobj) +void kobject_del(struct kobject *kobj) { if (!kobj) return; - sysfs_remove_dir(kobj); - unlink(kobj); -} -/** - * kobject_unregister - remove object from hierarchy and decrement refcount. - * @kobj: object going away. - */ - -void kobject_unregister(struct kobject * kobj) -{ - if (!kobj) - return; - pr_debug("kobject %s: unregistering\n",kobject_name(kobj)); - kobject_uevent(kobj, KOBJ_REMOVE); - kobject_del(kobj); - kobject_put(kobj); + sysfs_remove_dir(kobj); + kobj->state_in_sysfs = 0; + kobj_kset_leave(kobj); + kobject_put(kobj->parent); + kobj->parent = NULL; } /** - * kobject_get - increment refcount for object. - * @kobj: object. + * kobject_get - increment refcount for object. + * @kobj: object. */ - -struct kobject * kobject_get(struct kobject * kobj) +struct kobject *kobject_get(struct kobject *kobj) { if (kobj) kref_get(&kobj->kref); @@ -584,22 +537,42 @@ struct kobject * kobject_get(struct kobject * kobj) */ static void kobject_cleanup(struct kobject *kobj) { - struct kobj_type * t = get_ktype(kobj); - struct kset * s = kobj->kset; - struct kobject * parent = kobj->parent; - const char *name = kobj->k_name; + struct kobj_type *t = get_ktype(kobj); + const char *name = kobj->name; + + pr_debug("kobject: '%s' (%p): %s\n", + kobject_name(kobj), kobj, __func__); + + if (t && !t->release) + pr_debug("kobject: '%s' (%p): does not have a release() " + "function, it is broken and must be fixed.\n", + kobject_name(kobj), kobj); + + /* send "remove" if the caller did not do it but sent "add" */ + if (kobj->state_add_uevent_sent && !kobj->state_remove_uevent_sent) { + pr_debug("kobject: '%s' (%p): auto cleanup 'remove' event\n", + kobject_name(kobj), kobj); + kobject_uevent(kobj, KOBJ_REMOVE); + } + + /* remove from sysfs if the caller did not do it */ + if (kobj->state_in_sysfs) { + pr_debug("kobject: '%s' (%p): auto cleanup kobject_del\n", + kobject_name(kobj), kobj); + kobject_del(kobj); + } - pr_debug("kobject %s: cleaning up\n",kobject_name(kobj)); if (t && t->release) { + pr_debug("kobject: '%s' (%p): calling ktype release\n", + kobject_name(kobj), kobj); t->release(kobj); - /* If we have a release function, we can guess that this was - * not a statically allocated kobject, so we should be safe to - * free the name */ + } + + /* free name if we allocated it */ + if (name) { + pr_debug("kobject: '%s': free name\n", name); kfree(name); } - if (s) - kset_put(s); - kobject_put(parent); } static void kobject_release(struct kref *kref) @@ -608,20 +581,25 @@ static void kobject_release(struct kref *kref) } /** - * kobject_put - decrement refcount for object. - * @kobj: object. + * kobject_put - decrement refcount for object. + * @kobj: object. * - * Decrement the refcount, and if 0, call kobject_cleanup(). + * Decrement the refcount, and if 0, call kobject_cleanup(). */ -void kobject_put(struct kobject * kobj) +void kobject_put(struct kobject *kobj) { - if (kobj) + if (kobj) { + if (!kobj->state_initialized) + WARN(1, KERN_WARNING "kobject: '%s' (%p): is not " + "initialized, yet kobject_put() is being " + "called.\n", kobject_name(kobj), kobj); kref_put(&kobj->kref, kobject_release); + } } static void dynamic_kobj_release(struct kobject *kobj) { - pr_debug("%s: freeing %s\n", __FUNCTION__, kobject_name(kobj)); + pr_debug("kobject: (%p): %s\n", kobj, __func__); kfree(kobj); } @@ -638,7 +616,7 @@ static struct kobj_type dynamic_kobj_ktype = { * * If the kobject was not able to be created, NULL will be returned. * The kobject structure returned from here must be cleaned up with a - * call to kobject_put() and not kfree(), as kobject_init_ng() has + * call to kobject_put() and not kfree(), as kobject_init() has * already been called on this structure. */ struct kobject *kobject_create(void) @@ -649,7 +627,7 @@ struct kobject *kobject_create(void) if (!kobj) return NULL; - kobject_init_ng(kobj, &dynamic_kobj_ktype); + kobject_init(kobj, &dynamic_kobj_ktype); return kobj; } @@ -659,9 +637,9 @@ struct kobject *kobject_create(void) * @name: the name for the kset * @parent: the parent kobject of this kobject, if any. * - * This function creates a kset structure dynamically and registers it + * This function creates a kobject structure dynamically and registers it * with sysfs. When you are finished with this structure, call - * kobject_unregister() and the structure will be dynamically freed when + * kobject_put() and the structure will be dynamically freed when * it is no longer being used. * * If the kobject was not able to be created, NULL will be returned. @@ -675,10 +653,10 @@ struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) if (!kobj) return NULL; - retval = kobject_add_ng(kobj, parent, "%s", name); + retval = kobject_add(kobj, parent, "%s", name); if (retval) { printk(KERN_WARNING "%s: kobject_add error: %d\n", - __FUNCTION__, retval); + __func__, retval); kobject_put(kobj); kobj = NULL; } @@ -687,13 +665,12 @@ struct kobject *kobject_create_and_add(const char *name, struct kobject *parent) EXPORT_SYMBOL_GPL(kobject_create_and_add); /** - * kset_init - initialize a kset for use - * @k: kset + * kset_init - initialize a kset for use + * @k: kset */ - -void kset_init(struct kset * k) +void kset_init(struct kset *k) { - kobject_init(&k->kobj); + kobject_init_internal(&k->kobj); INIT_LIST_HEAD(&k->list); spin_lock_init(&k->list_lock); } @@ -723,28 +700,16 @@ static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr, return ret; } -struct sysfs_ops kobj_sysfs_ops = { +const struct sysfs_ops kobj_sysfs_ops = { .show = kobj_attr_show, .store = kobj_attr_store, }; /** - * kset_add - add a kset object to the hierarchy. - * @k: kset. + * kset_register - initialize and add a kset. + * @k: kset. */ - -int kset_add(struct kset * k) -{ - return kobject_add(&k->kobj); -} - - -/** - * kset_register - initialize and add a kset. - * @k: kset. - */ - -int kset_register(struct kset * k) +int kset_register(struct kset *k) { int err; @@ -752,46 +717,41 @@ int kset_register(struct kset * k) return -EINVAL; kset_init(k); - err = kset_add(k); + err = kobject_add_internal(&k->kobj); if (err) return err; kobject_uevent(&k->kobj, KOBJ_ADD); return 0; } - /** - * kset_unregister - remove a kset. - * @k: kset. + * kset_unregister - remove a kset. + * @k: kset. */ - -void kset_unregister(struct kset * k) +void kset_unregister(struct kset *k) { if (!k) return; - kobject_unregister(&k->kobj); + kobject_put(&k->kobj); } - /** - * kset_find_obj - search for object in kset. - * @kset: kset we're looking in. - * @name: object's name. + * kset_find_obj - search for object in kset. + * @kset: kset we're looking in. + * @name: object's name. * - * Lock kset via @kset->subsys, and iterate over @kset->list, - * looking for a matching kobject. If matching object is found - * take a reference and return the object. + * Lock kset via @kset->subsys, and iterate over @kset->list, + * looking for a matching kobject. If matching object is found + * take a reference and return the object. */ - -struct kobject * kset_find_obj(struct kset * kset, const char * name) +struct kobject *kset_find_obj(struct kset *kset, const char *name) { - struct list_head * entry; - struct kobject * ret = NULL; + struct kobject *k; + struct kobject *ret = NULL; spin_lock(&kset->list_lock); - list_for_each(entry,&kset->list) { - struct kobject * k = to_kobj(entry); - if (kobject_name(k) && !strcmp(kobject_name(k),name)) { + list_for_each_entry(k, &kset->list, entry) { + if (kobject_name(k) && !strcmp(kobject_name(k), name)) { ret = kobject_get(k); break; } @@ -803,7 +763,8 @@ struct kobject * kset_find_obj(struct kset * kset, const char * name) static void kset_release(struct kobject *kobj) { struct kset *kset = container_of(kobj, struct kset, kobj); - pr_debug("kset %s: now freed\n", kobject_name(kobj)); + pr_debug("kobject: '%s' (%p): %s\n", + kobject_name(kobj), kobj, __func__); kfree(kset); } @@ -828,15 +789,20 @@ static struct kobj_type kset_ktype = { * If the kset was not able to be created, NULL will be returned. */ static struct kset *kset_create(const char *name, - struct kset_uevent_ops *uevent_ops, + const struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj) { struct kset *kset; + int retval; kset = kzalloc(sizeof(*kset), GFP_KERNEL); if (!kset) return NULL; - kobject_set_name(&kset->kobj, name); + retval = kobject_set_name(&kset->kobj, name); + if (retval) { + kfree(kset); + return NULL; + } kset->uevent_ops = uevent_ops; kset->kobj.parent = parent_kobj; @@ -866,7 +832,7 @@ static struct kset *kset_create(const char *name, * If the kset was not able to be created, NULL will be returned. */ struct kset *kset_create_and_add(const char *name, - struct kset_uevent_ops *uevent_ops, + const struct kset_uevent_ops *uevent_ops, struct kobject *parent_kobj) { struct kset *kset; @@ -884,12 +850,123 @@ struct kset *kset_create_and_add(const char *name, } EXPORT_SYMBOL_GPL(kset_create_and_add); -EXPORT_SYMBOL(kobject_init); -EXPORT_SYMBOL(kobject_register); -EXPORT_SYMBOL(kobject_unregister); + +static DEFINE_SPINLOCK(kobj_ns_type_lock); +static const struct kobj_ns_type_operations *kobj_ns_ops_tbl[KOBJ_NS_TYPES]; + +int kobj_ns_type_register(const struct kobj_ns_type_operations *ops) +{ + enum kobj_ns_type type = ops->type; + int error; + + spin_lock(&kobj_ns_type_lock); + + error = -EINVAL; + if (type >= KOBJ_NS_TYPES) + goto out; + + error = -EINVAL; + if (type <= KOBJ_NS_TYPE_NONE) + goto out; + + error = -EBUSY; + if (kobj_ns_ops_tbl[type]) + goto out; + + error = 0; + kobj_ns_ops_tbl[type] = ops; + +out: + spin_unlock(&kobj_ns_type_lock); + return error; +} + +int kobj_ns_type_registered(enum kobj_ns_type type) +{ + int registered = 0; + + spin_lock(&kobj_ns_type_lock); + if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES)) + registered = kobj_ns_ops_tbl[type] != NULL; + spin_unlock(&kobj_ns_type_lock); + + return registered; +} + +const struct kobj_ns_type_operations *kobj_child_ns_ops(struct kobject *parent) +{ + const struct kobj_ns_type_operations *ops = NULL; + + if (parent && parent->ktype->child_ns_type) + ops = parent->ktype->child_ns_type(parent); + + return ops; +} + +const struct kobj_ns_type_operations *kobj_ns_ops(struct kobject *kobj) +{ + return kobj_child_ns_ops(kobj->parent); +} + + +const void *kobj_ns_current(enum kobj_ns_type type) +{ + const void *ns = NULL; + + spin_lock(&kobj_ns_type_lock); + if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && + kobj_ns_ops_tbl[type]) + ns = kobj_ns_ops_tbl[type]->current_ns(); + spin_unlock(&kobj_ns_type_lock); + + return ns; +} + +const void *kobj_ns_netlink(enum kobj_ns_type type, struct sock *sk) +{ + const void *ns = NULL; + + spin_lock(&kobj_ns_type_lock); + if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && + kobj_ns_ops_tbl[type]) + ns = kobj_ns_ops_tbl[type]->netlink_ns(sk); + spin_unlock(&kobj_ns_type_lock); + + return ns; +} + +const void *kobj_ns_initial(enum kobj_ns_type type) +{ + const void *ns = NULL; + + spin_lock(&kobj_ns_type_lock); + if ((type > KOBJ_NS_TYPE_NONE) && (type < KOBJ_NS_TYPES) && + kobj_ns_ops_tbl[type]) + ns = kobj_ns_ops_tbl[type]->initial_ns(); + spin_unlock(&kobj_ns_type_lock); + + return ns; +} + +/* + * kobj_ns_exit - invalidate a namespace tag + * + * @type: the namespace type (i.e. KOBJ_NS_TYPE_NET) + * @ns: the actual namespace being invalidated + * + * This is called when a tag is no longer valid. For instance, + * when a network namespace exits, it uses this helper to + * make sure no sb's sysfs_info points to the now-invalidated + * netns. + */ +void kobj_ns_exit(enum kobj_ns_type type, const void *ns) +{ + sysfs_exit_ns(type, ns); +} + + EXPORT_SYMBOL(kobject_get); EXPORT_SYMBOL(kobject_put); -EXPORT_SYMBOL(kobject_add); EXPORT_SYMBOL(kobject_del); EXPORT_SYMBOL(kset_register);