Release 4.16 lib/kobject.c
// SPDX-License-Identifier: GPL-2.0
/*
* kobject.c - library routines for handling generic kernel objects
*
* Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org>
* Copyright (c) 2006-2007 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2006-2007 Novell Inc.
*
* Please see the file Documentation/kobject.txt for critical information
* about using the kobject interface.
*/
#include <linux/kobject.h>
#include <linux/string.h>
#include <linux/export.h>
#include <linux/stat.h>
#include <linux/slab.h>
#include <linux/random.h>
/**
* kobject_namespace - return @kobj's namespace tag
* @kobj: kobject in question
*
* Returns namespace tag of @kobj if its parent has namespace ops enabled
* and thus @kobj should have a namespace tag associated with it. Returns
* %NULL otherwise.
*/
const void *kobject_namespace(struct kobject *kobj)
{
const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj);
if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE)
return NULL;
return kobj->ktype->namespace(kobj);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tejun Heo | 46 | 97.87% | 1 | 50.00% |
Linus Torvalds | 1 | 2.13% | 1 | 50.00% |
Total | 47 | 100.00% | 2 | 100.00% |
/*
* 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)
{
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++) {
error = sysfs_create_file(kobj, attr);
if (error)
break;
}
}
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 57 | 67.06% | 4 | 57.14% |
Greg Kroah-Hartman | 26 | 30.59% | 2 | 28.57% |
Mika Kukkonen | 2 | 2.35% | 1 | 14.29% |
Total | 85 | 100.00% | 7 | 100.00% |
static int create_dir(struct kobject *kobj)
{
const struct kobj_ns_type_operations *ops;
int error;
error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj));
if (error)
return error;
error = populate_dir(kobj);
if (error) {
sysfs_remove_dir(kobj);
return error;
}
/*
* @kobj->sd may be deleted by an ancestor going away. Hold an
* extra reference so that it stays until @kobj is gone.
*/
sysfs_get(kobj->sd);
/*
* If @kobj has ns_ops, its children need to be filtered based on
* their namespace tags. Enable namespace support on @kobj->sd.
*/
ops = kobj_child_ns_ops(kobj);
if (ops) {
BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE);
BUG_ON(ops->type >= KOBJ_NS_TYPES);
BUG_ON(!kobj_ns_type_registered(ops->type));
sysfs_enable_ns(kobj->sd);
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Tejun Heo | 78 | 64.46% | 4 | 66.67% |
Greg Kroah-Hartman | 43 | 35.54% | 2 | 33.33% |
Total | 121 | 100.00% | 6 | 100.00% |
static int get_kobj_path_length(struct kobject *kobj)
{
int length = 1;
struct kobject *parent = kobj;
/* walk up the ancestors until we hit the one pointing to the
* root.
* Add 1 to strlen for leading '/' of each level.
*/
do {
if (kobject_name(parent) == NULL)
return 0;
length += strlen(kobject_name(parent)) + 1;
parent = parent->parent;
} while (parent);
return length;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 50 | 76.92% | 2 | 50.00% |
Chuck Ebbert | 12 | 18.46% | 1 | 25.00% |
Patrick Mochel | 3 | 4.62% | 1 | 25.00% |
Total | 65 | 100.00% | 4 | 100.00% |
static void fill_kobj_path(struct kobject *kobj, char *path, int length)
{
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);
*(path + --length) = '/';
}
pr_debug("kobject: '%s' (%p): %s: path = '%s'\n", kobject_name(kobj),
kobj, __func__, path);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 91 | 92.86% | 2 | 50.00% |
Patrick Mochel | 6 | 6.12% | 1 | 25.00% |
Harvey Harrison | 1 | 1.02% | 1 | 25.00% |
Total | 98 | 100.00% | 4 | 100.00% |
/**
* kobject_get_path - generate and return the path associated with a given kobj and kset pair.
*
* @kobj: kobject in question, with which to build the path
* @gfp_mask: the allocation type used to allocate the path
*
* The result must be freed by the caller with kfree().
*/
char *kobject_get_path(struct kobject *kobj, gfp_t gfp_mask)
{
char *path;
int len;
len = get_kobj_path_length(kobj);
if (len == 0)
return NULL;
path = kzalloc(len, gfp_mask);
if (!path)
return NULL;
fill_kobj_path(kobj, path, len);
return path;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Robert Love | 55 | 83.33% | 1 | 25.00% |
Chuck Ebbert | 9 | 13.64% | 1 | 25.00% |
Burman Yan | 1 | 1.52% | 1 | 25.00% |
Al Viro | 1 | 1.52% | 1 | 25.00% |
Total | 66 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(kobject_get_path);
/* add the kobject to its kset's list */
static void kobj_kset_join(struct kobject *kobj)
{
if (!kobj->kset)
return;
kset_get(kobj->kset);
spin_lock(&kobj->kset->list_lock);
list_add_tail(&kobj->entry, &kobj->kset->list);
spin_unlock(&kobj->kset->list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kay Sievers | 32 | 52.46% | 1 | 25.00% |
Patrick Mochel | 22 | 36.07% | 1 | 25.00% |
Greg Kroah-Hartman | 7 | 11.48% | 2 | 50.00% |
Total | 61 | 100.00% | 4 | 100.00% |
/* remove the kobject from its kset's list */
static void kobj_kset_leave(struct kobject *kobj)
{
if (!kobj->kset)
return;
spin_lock(&kobj->kset->list_lock);
list_del_init(&kobj->entry);
spin_unlock(&kobj->kset->list_lock);
kset_put(kobj->kset);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 39 | 72.22% | 1 | 25.00% |
Kay Sievers | 8 | 14.81% | 1 | 25.00% |
Greg Kroah-Hartman | 4 | 7.41% | 1 | 25.00% |
Alan Stern | 3 | 5.56% | 1 | 25.00% |
Total | 54 | 100.00% | 4 | 100.00% |
static void kobject_init_internal(struct kobject *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;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kay Sievers | 25 | 43.86% | 1 | 25.00% |
Greg Kroah-Hartman | 24 | 42.11% | 1 | 25.00% |
Patrick Mochel | 5 | 8.77% | 1 | 25.00% |
Alan Stern | 3 | 5.26% | 1 | 25.00% |
Total | 57 | 100.00% | 4 | 100.00% |
static int kobject_add_internal(struct kobject *kobj)
{
int error = 0;
struct kobject *parent;
if (!kobj)
return -ENOENT;
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);
/* join kset if set, use it as parent if we do not already have one */
if (kobj->kset) {
if (!parent)
parent = kobject_get(&kobj->kset->kobj);
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) : "<NULL>",
kobj->kset ? kobject_name(&kobj->kset->kobj) : "<NULL>");
error = create_dir(kobj);
if (error) {
kobj_kset_leave(kobj);
kobject_put(parent);
kobj->parent = NULL;
/* be noisy on error issues */
if (error == -EEXIST)
WARN(1, "%s failed for %s with "
"-EEXIST, don't try to register things with "
"the same name in the same directory.\n",
__func__, kobject_name(kobj));
else
WARN(1, "%s failed for %s (error: %d parent: %s)\n",
__func__, kobject_name(kobj), error,
parent ? kobject_name(parent) : "'none'");
} else
kobj->state_in_sysfs = 1;
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 89 | 37.87% | 8 | 34.78% |
Greg Kroah-Hartman | 67 | 28.51% | 10 | 43.48% |
Kay Sievers | 57 | 24.26% | 2 | 8.70% |
Dan J Williams | 16 | 6.81% | 1 | 4.35% |
Arjan van de Ven | 3 | 1.28% | 1 | 4.35% |
Harvey Harrison | 3 | 1.28% | 1 | 4.35% |
Total | 235 | 100.00% | 23 | 100.00% |
/**
* 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.
*/
int kobject_set_name_vargs(struct kobject *kobj, const char *fmt,
va_list vargs)
{
const char *s;
if (kobj->name && !fmt)
return 0;
s = kvasprintf_const(GFP_KERNEL, fmt, vargs);
if (!s)
return -ENOMEM;
/*
* ewww... some of these buggers have '/' in the name ... If
* that's the case, we need to make sure we have an actual
* allocated copy to modify, since kvasprintf_const may have
* returned something from .rodata.
*/
if (strchr(s, '/')) {
char *t;
t = kstrdup(s, GFP_KERNEL);
kfree_const(s);
if (!t)
return -ENOMEM;
strreplace(t, '/', '!');
s = t;
}
kfree_const(kobj->name);
kobj->name = s;
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Rasmus Villemoes | 61 | 49.59% | 2 | 33.33% |
Patrick Mochel | 28 | 22.76% | 1 | 16.67% |
Kay Sievers | 24 | 19.51% | 2 | 33.33% |
Greg Kroah-Hartman | 10 | 8.13% | 1 | 16.67% |
Total | 123 | 100.00% | 6 | 100.00% |
/**
* kobject_set_name - Set the name of a kobject
* @kobj: struct kobject to set the name of
* @fmt: format string used to build the name
*
* This sets the name of the kobject. If you have already added the
* kobject to the system, you must call kobject_rename() in order to
* change the name of the kobject.
*/
int kobject_set_name(struct kobject *kobj, const char *fmt, ...)
{
va_list vargs;
int retval;
va_start(vargs, fmt);
retval = kobject_set_name_vargs(kobj, fmt, vargs);
va_end(vargs);
return retval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 25 | 51.02% | 1 | 25.00% |
Patrick Mochel | 10 | 20.41% | 1 | 25.00% |
Andrew Morton | 10 | 20.41% | 1 | 25.00% |
Kay Sievers | 4 | 8.16% | 1 | 25.00% |
Total | 49 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(kobject_set_name);
/**
* kobject_init - initialize a kobject structure
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
*
* This function will properly initialize a kobject such that it can then
* be passed to the kobject_add() call.
*
* After this function is called, the kobject MUST be cleaned up by a call
* to kobject_put(), not by a call to kfree directly to ensure that all of
* the memory is cleaned up properly.
*/
void kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
char *err_str;
if (!kobj) {
err_str = "invalid kobject pointer!";
goto error;
}
if (!ktype) {
err_str = "must have a ktype to be initialized properly!\n";
goto error;
}
if (kobj->state_initialized) {
/* do not error out as sometimes we can recover */
printk(KERN_ERR "kobject (%p): tried to init an initialized "
"object, something is seriously wrong.\n", kobj);
dump_stack();
}
kobject_init_internal(kobj);
kobj->ktype = ktype;
return;
error:
printk(KERN_ERR "kobject (%p): %s\n", kobj, err_str);
dump_stack();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 87 | 91.58% | 3 | 75.00% |
Kay Sievers | 8 | 8.42% | 1 | 25.00% |
Total | 95 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL(kobject_init);
static __printf(3, 0) int kobject_add_varg(struct kobject *kobj,
struct kobject *parent,
const char *fmt, va_list vargs)
{
int retval;
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_internal(kobj);
}
/**
* 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.
*
* The kobject name is set and added to the kobject hierarchy in this
* function.
*
* If @parent is set, then the parent of the @kobj will be set to it.
* If @parent is NULL, then the parent of the @kobj will be set to the
* kobject associated with the kset assigned to this kobject. If no kset
* is assigned to the kobject, then the kobject will be located in the
* root of the sysfs tree.
*
* If this function returns an error, kobject_put() must be called to
* properly clean up the memory associated with the object.
* 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 "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(struct kobject *kobj, struct kobject *parent,
const char *fmt, ...)
{
va_list args;
int retval;
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);
/**
* kobject_init_and_add - initialize a kobject structure and add it to the kobject hierarchy
* @kobj: pointer to the kobject to initialize
* @ktype: pointer to the ktype for this kobject.
* @parent: pointer to the parent of this kobject.
* @fmt: the name of the kobject.
*
* 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, ...)
{
va_list args;
int retval;
kobject_init(kobj, ktype);
va_start(args, fmt);
retval = kobject_add_varg(kobj, parent, fmt, args);
va_end(args);
return retval;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 68 | 100.00% | 2 | 100.00% |
Total | 68 | 100.00% | 2 | 100.00% |
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
*
* 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 error = 0;
const char *devpath = NULL;
const char *dup_name = NULL, *name;
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;
name = dup_name = kstrdup_const(new_name, GFP_KERNEL);
if (!name) {
error = -ENOMEM;
goto out;
}
error = sysfs_rename_dir_ns(kobj, new_name, kobject_namespace(kobj));
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. */
kobject_uevent_env(kobj, KOBJ_MOVE, envp);
out:
kfree_const(dup_name);
kfree(devpath_string);
kfree(devpath);
kobject_put(kobj);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jean Tourrilhes | 120 | 48.39% | 1 | 12.50% |
Eric W. Biedermann | 80 | 32.26% | 2 | 25.00% |
Greg Kroah-Hartman | 27 | 10.89% | 1 | 12.50% |
Maneesh Soni | 12 | 4.84% | 1 | 12.50% |
Tejun Heo | 6 | 2.42% | 1 | 12.50% |
Rasmus Villemoes | 2 | 0.81% | 1 | 12.50% |
Dmitry Torokhov | 1 | 0.40% | 1 | 12.50% |
Total | 248 | 100.00% | 8 | 100.00% |
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)
*/
int kobject_move(struct kobject *kobj, struct kobject *new_parent)
{
int error;
struct kobject *old_parent;
const char *devpath = NULL;
char *devpath_string = NULL;
char *envp[2];
kobj = kobject_get(kobj);
if (!kobj)
return -EINVAL;
new_parent = kobject_get(new_parent);
if (!new_parent) {
if (kobj->kset)
new_parent = kobject_get(&kobj->kset->kobj);
}
/* old object path */
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;
error = sysfs_move_dir_ns(kobj, new_parent, kobject_namespace(kobj));
if (error)
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);
return error;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Cornelia Huck | 229 | 93.85% | 2 | 50.00% |
Dmitriy Monakhov | 9 | 3.69% | 1 | 25.00% |
Tejun Heo | 6 | 2.46% | 1 | 25.00% |
Total | 244 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(kobject_move);
/**
* kobject_del - unlink kobject from hierarchy.
* @kobj: object.
*/
void kobject_del(struct kobject *kobj)
{
struct kernfs_node *sd;
if (!kobj)
return;
sd = kobj->sd;
sysfs_remove_dir(kobj);
sysfs_put(sd);
kobj->state_in_sysfs = 0;
kobj_kset_leave(kobj);
kobject_put(kobj->parent);
kobj->parent = NULL;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kay Sievers | 20 | 32.79% | 1 | 14.29% |
Patrick Mochel | 19 | 31.15% | 3 | 42.86% |
Tejun Heo | 16 | 26.23% | 2 | 28.57% |
Greg Kroah-Hartman | 6 | 9.84% | 1 | 14.29% |
Total | 61 | 100.00% | 7 | 100.00% |
EXPORT_SYMBOL(kobject_del);
/**
* kobject_get - increment refcount for object.
* @kobj: object.
*/
struct kobject *kobject_get(struct kobject *kobj)
{
if (kobj) {
if (!kobj->state_initialized)
WARN(1, KERN_WARNING "kobject: '%s' (%p): is not "
"initialized, yet kobject_get() is being "
"called.\n", kobject_name(kobj), kobj);
kref_get(&kobj->kref);
}
return kobj;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Ethan Zhao | 26 | 49.06% | 1 | 20.00% |
Patrick Mochel | 24 | 45.28% | 2 | 40.00% |
Greg Kroah-Hartman | 3 | 5.66% | 2 | 40.00% |
Total | 53 | 100.00% | 5 | 100.00% |
EXPORT_SYMBOL(kobject_get);
struct kobject * __must_check kobject_get_unless_zero(struct kobject *kobj)
{
if (!kobj)
return NULL;
if (!kref_get_unless_zero(&kobj->kref))
kobj = NULL;
return kobj;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Linus Torvalds | 30 | 76.92% | 1 | 33.33% |
Jan Kara | 8 | 20.51% | 1 | 33.33% |
Anatol Pomozov | 1 | 2.56% | 1 | 33.33% |
Total | 39 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(kobject_get_unless_zero);
/*
* kobject_cleanup - free kobject resources.
* @kobj: object to cleanup
*/
static void kobject_cleanup(struct kobject *kobj)
{
struct kobj_type *t = get_ktype(kobj);
const char *name = kobj->name;
pr_debug("kobject: '%s' (%p): %s, parent %p\n",
kobject_name(kobj), kobj, __func__, kobj->parent);
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);
}
if (t && t->release) {
pr_debug("kobject: '%s' (%p): calling ktype release\n",
kobject_name(kobj), kobj);
t->release(kobj);
}
/* free name if we allocated it */
if (name) {
pr_debug("kobject: '%s': free name\n", name);
kfree_const(name);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Kay Sievers | 104 | 58.76% | 2 | 14.29% |
Patrick Mochel | 50 | 28.25% | 6 | 42.86% |
Greg Kroah-Hartman | 16 | 9.04% | 3 | 21.43% |
Russell King | 5 | 2.82% | 1 | 7.14% |
Harvey Harrison | 1 | 0.56% | 1 | 7.14% |
Rasmus Villemoes | 1 | 0.56% | 1 | 7.14% |
Total | 177 | 100.00% | 14 | 100.00% |
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
static void kobject_delayed_cleanup(struct work_struct *work)
{
kobject_cleanup(container_of(to_delayed_work(work),
struct kobject, release));
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 27 | 100.00% | 1 | 100.00% |
Total | 27 | 100.00% | 1 | 100.00% |
#endif
static void kobject_release(struct kref *kref)
{
struct kobject *kobj = container_of(kref, struct kobject, kref);
#ifdef CONFIG_DEBUG_KOBJECT_RELEASE
unsigned long delay = HZ + HZ * (get_random_int() & 0x3);
pr_info("kobject: '%s' (%p): %s, parent %p (delayed %ld)\n",
kobject_name(kobj), kobj, __func__, kobj->parent, delay);
INIT_DELAYED_WORK(&kobj->release, kobject_delayed_cleanup);
schedule_delayed_work(&kobj->release, delay);
#else
kobject_cleanup(kobj);
#endif
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Russell King | 51 | 54.84% | 1 | 25.00% |
Greg Kroah-Hartman | 22 | 23.66% | 1 | 25.00% |
Björn Helgaas | 19 | 20.43% | 1 | 25.00% |
Fengguang Wu | 1 | 1.08% | 1 | 25.00% |
Total | 93 | 100.00% | 4 | 100.00% |
/**
* kobject_put - decrement refcount for object.
* @kobj: object.
*
* Decrement the refcount, and if 0, call kobject_cleanup().
*/
void kobject_put(struct kobject *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);
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 29 | 58.00% | 2 | 33.33% |
Patrick Mochel | 18 | 36.00% | 3 | 50.00% |
Arjan van de Ven | 3 | 6.00% | 1 | 16.67% |
Total | 50 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL(kobject_put);
static void dynamic_kobj_release(struct kobject *kobj)
{
pr_debug("kobject: (%p): %s\n", kobj, __func__);
kfree(kobj);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jun'ichi Nomura | 15 | 60.00% | 1 | 20.00% |
Greg Kroah-Hartman | 8 | 32.00% | 2 | 40.00% |
Kay Sievers | 1 | 4.00% | 1 | 20.00% |
Harvey Harrison | 1 | 4.00% | 1 | 20.00% |
Total | 25 | 100.00% | 5 | 100.00% |
static struct kobj_type dynamic_kobj_ktype = {
.release = dynamic_kobj_release,
.sysfs_ops = &kobj_sysfs_ops,
};
/**
* kobject_create - create a struct kobject dynamically
*
* This function creates a kobject structure dynamically and sets it up
* to be a "dynamic" kobject with a default release function set up.
*
* 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() has
* already been called on this structure.
*/
struct kobject *kobject_create(void)
{
struct kobject *kobj;
kobj = kzalloc(sizeof(*kobj), GFP_KERNEL);
if (!kobj)
return NULL;
kobject_init(kobj, &dynamic_kobj_ktype);
return kobj;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 44 | 95.65% | 2 | 66.67% |
Jun'ichi Nomura | 2 | 4.35% | 1 | 33.33% |
Total | 46 | 100.00% | 3 | 100.00% |
/**
* kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
*
* @name: the name for the kobject
* @parent: the parent kobject of this kobject, if any.
*
* This function creates a kobject structure dynamically and registers it
* with sysfs. When you are finished with this structure, call
* 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.
*/
struct kobject *kobject_create_and_add(const char *name, struct kobject *parent)
{
struct kobject *kobj;
int retval;
kobj = kobject_create();
if (!kobj)
return NULL;
retval = kobject_add(kobj, parent, "%s", name);
if (retval) {
printk(KERN_WARNING "%s: kobject_add error: %d\n",
__func__, retval);
kobject_put(kobj);
kobj = NULL;
}
return kobj;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Greg Kroah-Hartman | 76 | 96.20% | 2 | 50.00% |
Jun'ichi Nomura | 2 | 2.53% | 1 | 25.00% |
Harvey Harrison | 1 | 1.27% | 1 | 25.00% |
Total | 79 | 100.00% | 4 | 100.00% |
EXPORT_SYMBOL_GPL(kobject_create_and_add);
/**
* kset_init - initialize a kset for use
* @k: kset
*/
void kset_init(struct kset *k)
{
kobject_init_internal(&k->kobj);
INIT_LIST_HEAD(&k->list);
spin_lock_init(&k->list_lock);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Patrick Mochel | 25 | 73.53% | 2 | 50.00% |
Greg Kroah-Hartman | 9 | 26.47% | 2 | 50.00% |
Total | 34 | 100.00% | 4 | 100.00% |
/* default kobject attribute operations */
static ssize_t kobj_attr_show(struct kobject *kobj, struct