2005-04-17 02:20:36 +04:00
/*
* kobject . c - library routines for handling generic kernel objects
*
* Copyright ( c ) 2002 - 2003 Patrick Mochel < mochel @ osdl . org >
2007-09-28 01:48:53 +04:00
* Copyright ( c ) 2006 - 2007 Greg Kroah - Hartman < greg @ kroah . com >
* Copyright ( c ) 2006 - 2007 Novell Inc .
2005-04-17 02:20:36 +04:00
*
* This file is released under the GPLv2 .
*
*
* Please see the file Documentation / kobject . txt for critical information
* about using the kobject interface .
*/
# include <linux/kobject.h>
# include <linux/string.h>
2011-11-17 06:29:17 +04:00
# include <linux/export.h>
2005-04-17 02:20:36 +04:00
# include <linux/stat.h>
2005-10-31 02:03:48 +03:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
2008-01-25 08:59:04 +03:00
/*
* populate_dir - populate directory with attributes .
* @ kobj : object we ' re working on .
2005-04-17 02:20:36 +04:00
*
2008-01-25 08:59:04 +03:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
static int populate_dir ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2008-01-25 08:59:04 +03:00
struct kobj_type * t = get_ktype ( kobj ) ;
struct attribute * attr ;
2005-04-17 02:20:36 +04:00
int error = 0 ;
int i ;
2008-01-25 08:59:04 +03:00
2005-04-17 02:20:36 +04:00
if ( t & & t - > default_attrs ) {
for ( i = 0 ; ( attr = t - > default_attrs [ i ] ) ! = NULL ; i + + ) {
2008-01-25 08:59:04 +03:00
error = sysfs_create_file ( kobj , attr ) ;
if ( error )
2005-04-17 02:20:36 +04:00
break ;
}
}
return error ;
}
2008-01-25 08:59:04 +03:00
static int create_dir ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
int error = 0 ;
2012-04-20 17:25:53 +04:00
error = sysfs_create_dir ( kobj ) ;
if ( ! error ) {
error = populate_dir ( kobj ) ;
if ( error )
sysfs_remove_dir ( kobj ) ;
2005-04-17 02:20:36 +04:00
}
return error ;
}
static int get_kobj_path_length ( struct kobject * kobj )
{
int length = 1 ;
2008-01-25 08:59:04 +03:00
struct kobject * parent = kobj ;
2005-04-17 02:20:36 +04:00
2008-01-25 08:59:04 +03:00
/* walk up the ancestors until we hit the one pointing to the
2005-04-17 02:20:36 +04:00
* root .
* Add 1 to strlen for leading ' / ' of each level .
*/
do {
2006-01-13 04:02:00 +03:00
if ( kobject_name ( parent ) = = NULL )
return 0 ;
2005-04-17 02:20:36 +04:00
length + = strlen ( kobject_name ( parent ) ) + 1 ;
parent = parent - > parent ;
} while ( parent ) ;
return length ;
}
static void fill_kobj_path ( struct kobject * kobj , char * path , int length )
{
2008-01-25 08:59:04 +03:00
struct kobject * parent ;
2005-04-17 02:20:36 +04:00
- - length ;
for ( parent = kobj ; parent ; parent = parent - > parent ) {
int cur = strlen ( kobject_name ( parent ) ) ;
/* back up enough to print this name with '/' */
length - = cur ;
2008-01-25 08:59:04 +03:00
strncpy ( path + length , kobject_name ( parent ) , cur ) ;
2005-04-17 02:20:36 +04:00
* ( path + - - length ) = ' / ' ;
}
2007-11-29 10:49:41 +03:00
pr_debug ( " kobject: '%s' (%p): %s: path = '%s' \n " , kobject_name ( kobj ) ,
2008-04-30 11:55:08 +04:00
kobj , __func__ , path ) ;
2005-04-17 02:20:36 +04:00
}
/**
2007-02-10 12:45:59 +03:00
* kobject_get_path - generate and return the path associated with a given kobj and kset pair .
2005-04-17 02:20:36 +04:00
*
* @ kobj : kobject in question , with which to build the path
* @ gfp_mask : the allocation type used to allocate the path
2007-02-10 12:45:59 +03:00
*
* The result must be freed by the caller with kfree ( ) .
2005-04-17 02:20:36 +04:00
*/
2005-10-21 11:18:50 +04:00
char * kobject_get_path ( struct kobject * kobj , gfp_t gfp_mask )
2005-04-17 02:20:36 +04:00
{
char * path ;
int len ;
len = get_kobj_path_length ( kobj ) ;
2006-01-13 04:02:00 +03:00
if ( len = = 0 )
return NULL ;
2006-12-07 07:38:51 +03:00
path = kzalloc ( len , gfp_mask ) ;
2005-04-17 02:20:36 +04:00
if ( ! path )
return NULL ;
fill_kobj_path ( kobj , path , len ) ;
return path ;
}
2006-10-11 09:43:58 +04:00
EXPORT_SYMBOL_GPL ( kobject_get_path ) ;
2005-04-17 02:20:36 +04:00
2007-12-19 03:40:42 +03:00
/* add the kobject to its kset's list */
static void kobj_kset_join ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2007-12-19 03:40:42 +03:00
if ( ! kobj - > kset )
2007-01-18 23:23:51 +03:00
return ;
2007-12-19 03:40:42 +03:00
kset_get ( kobj - > kset ) ;
spin_lock ( & kobj - > kset - > list_lock ) ;
list_add_tail ( & kobj - > entry , & kobj - > kset - > list ) ;
spin_unlock ( & kobj - > kset - > list_lock ) ;
2005-04-17 02:20:36 +04:00
}
2007-12-19 03:40:42 +03:00
/* remove the kobject from its kset's list */
static void kobj_kset_leave ( struct kobject * kobj )
{
if ( ! kobj - > kset )
return ;
2005-04-17 02:20:36 +04:00
2007-12-19 03:40:42 +03:00
spin_lock ( & kobj - > kset - > list_lock ) ;
list_del_init ( & kobj - > entry ) ;
spin_unlock ( & kobj - > kset - > list_lock ) ;
kset_put ( kobj - > kset ) ;
}
2005-04-17 02:20:36 +04:00
2008-01-25 08:59:04 +03:00
static void kobject_init_internal ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2007-12-19 03:40:42 +03:00
if ( ! kobj )
return ;
kref_init ( & kobj - > kref ) ;
INIT_LIST_HEAD ( & kobj - > entry ) ;
2008-02-26 20:36:38 +03:00
kobj - > state_in_sysfs = 0 ;
kobj - > state_add_uevent_sent = 0 ;
kobj - > state_remove_uevent_sent = 0 ;
kobj - > state_initialized = 1 ;
2005-04-17 02:20:36 +04:00
}
2007-12-19 03:40:42 +03:00
2007-12-18 09:05:35 +03:00
static int kobject_add_internal ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
int error = 0 ;
2008-01-25 08:59:04 +03:00
struct kobject * parent ;
2005-04-17 02:20:36 +04:00
2007-12-19 03:40:42 +03:00
if ( ! kobj )
2005-04-17 02:20:36 +04:00
return - ENOENT ;
2007-12-19 03:40:42 +03:00
2007-12-20 04:09:39 +03:00
if ( ! kobj - > name | | ! kobj - > name [ 0 ] ) {
2008-07-25 12:45:55 +04:00
WARN ( 1 , " kobject: (%p): attempted to be registered with empty "
2007-11-29 10:49:41 +03:00
" name! \n " , kobj ) ;
2006-01-21 01:08:59 +03:00
return - EINVAL ;
}
2005-04-17 02:20:36 +04:00
2007-12-19 03:40:42 +03:00
parent = kobject_get ( kobj - > parent ) ;
2005-04-17 02:20:36 +04:00
2007-12-19 03:40:42 +03:00
/* join kset if set, use it as parent if we do not already have one */
2005-04-17 02:20:36 +04:00
if ( kobj - > kset ) {
2007-12-19 03:40:42 +03:00
if ( ! parent )
2005-04-17 02:20:36 +04:00
parent = kobject_get ( & kobj - > kset - > kobj ) ;
2007-12-19 03:40:42 +03:00
kobj_kset_join ( kobj ) ;
2007-03-10 14:00:10 +03:00
kobj - > parent = parent ;
2005-04-17 02:20:36 +04:00
}
2007-12-19 03:40:42 +03:00
pr_debug ( " kobject: '%s' (%p): %s: parent: '%s', set: '%s' \n " ,
2008-04-30 11:55:08 +04:00
kobject_name ( kobj ) , kobj , __func__ ,
2007-12-19 03:40:42 +03:00
parent ? kobject_name ( parent ) : " <NULL> " ,
2008-01-25 08:59:04 +03:00
kobj - > kset ? kobject_name ( & kobj - > kset - > kobj ) : " <NULL> " ) ;
2007-12-19 03:40:42 +03:00
2007-07-31 14:15:08 +04:00
error = create_dir ( kobj ) ;
2005-04-17 02:20:36 +04:00
if ( error ) {
2007-12-19 03:40:42 +03:00
kobj_kset_leave ( kobj ) ;
kobject_put ( parent ) ;
kobj - > parent = NULL ;
2006-03-21 00:17:13 +03:00
/* be noisy on error issues */
if ( error = = - EEXIST )
2012-04-07 00:41:15 +04:00
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 ) ) ;
2006-03-21 00:17:13 +03:00
else
2012-04-07 00:41:15 +04:00
WARN ( 1 , " %s failed for %s (error: %d parent: %s) \n " ,
__func__ , kobject_name ( kobj ) , error ,
parent ? kobject_name ( parent ) : " 'none' " ) ;
2007-12-19 03:40:42 +03:00
} else
kobj - > state_in_sysfs = 1 ;
2005-04-17 02:20:36 +04:00
return error ;
}
2007-11-30 02:32:47 +03: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 .
*/
2009-01-25 17:17:37 +03:00
int kobject_set_name_vargs ( struct kobject * kobj , const char * fmt ,
2007-11-30 02:32:47 +03:00
va_list vargs )
{
2008-05-07 00:24:04 +04:00
const char * old_name = kobj - > name ;
char * s ;
2007-11-30 02:32:47 +03:00
2009-04-19 02:05:45 +04:00
if ( kobj - > name & & ! fmt )
return 0 ;
2008-04-30 04:06:29 +04:00
kobj - > name = kvasprintf ( GFP_KERNEL , fmt , vargs ) ;
if ( ! kobj - > name )
return - ENOMEM ;
2007-11-30 02:32:47 +03:00
2008-05-07 00:24:04 +04:00
/* ewww... some of these buggers have '/' in the name ... */
2008-07-23 03:25:01 +04:00
while ( ( s = strchr ( kobj - > name , ' / ' ) ) )
2008-05-07 00:24:04 +04:00
s [ 0 ] = ' ! ' ;
kfree ( old_name ) ;
2007-11-30 02:32:47 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
/**
2007-12-04 09:45:47 +03:00
* kobject_set_name - Set the name of a kobject
2007-11-30 02:32:47 +03:00
* @ kobj : struct kobject to set the name of
2007-12-04 09:45:47 +03:00
* @ fmt : format string used to build the name
2005-04-17 02:20:36 +04:00
*
2007-12-04 09:45:47 +03:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2007-11-30 02:32:47 +03:00
int kobject_set_name ( struct kobject * kobj , const char * fmt , . . . )
2005-04-17 02:20:36 +04:00
{
2008-04-30 04:06:29 +04:00
va_list vargs ;
2007-11-30 02:32:47 +03:00
int retval ;
2005-04-17 02:20:36 +04:00
2008-04-30 04:06:29 +04:00
va_start ( vargs , fmt ) ;
retval = kobject_set_name_vargs ( kobj , fmt , vargs ) ;
va_end ( vargs ) ;
2005-04-17 02:20:36 +04:00
2007-11-30 02:32:47 +03:00
return retval ;
2005-04-17 02:20:36 +04:00
}
EXPORT_SYMBOL ( kobject_set_name ) ;
2007-12-04 08:31:08 +03:00
/**
2007-12-18 09:05:35 +03:00
* kobject_init - initialize a kobject structure
2007-12-04 08:31:08 +03:00
* @ 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 .
*/
2007-12-18 09:05:35 +03:00
void kobject_init ( struct kobject * kobj , struct kobj_type * ktype )
2007-12-04 08:31:08 +03:00
{
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 ;
}
2007-12-19 03:40:42 +03:00
if ( kobj - > state_initialized ) {
2007-12-04 08:31:08 +03:00
/* do not error out as sometimes we can recover */
2007-12-19 03:40:42 +03:00
printk ( KERN_ERR " kobject (%p): tried to init an initialized "
" object, something is seriously wrong. \n " , kobj ) ;
2007-12-04 08:31:08 +03:00
dump_stack ( ) ;
}
2008-02-26 20:36:38 +03:00
kobject_init_internal ( kobj ) ;
2007-12-04 08:31:08 +03:00
kobj - > ktype = ktype ;
return ;
error :
2007-12-19 03:40:42 +03:00
printk ( KERN_ERR " kobject (%p): %s \n " , kobj , err_str ) ;
2007-12-04 08:31:08 +03:00
dump_stack ( ) ;
}
2007-12-18 09:05:35 +03:00
EXPORT_SYMBOL ( kobject_init ) ;
2007-12-04 08:31:08 +03:00
2007-12-04 08:31:08 +03:00
static int kobject_add_varg ( struct kobject * kobj , struct kobject * parent ,
const char * fmt , va_list vargs )
{
int retval ;
2008-04-30 04:06:29 +04:00
retval = kobject_set_name_vargs ( kobj , fmt , vargs ) ;
2007-12-04 08:31:08 +03:00
if ( retval ) {
printk ( KERN_ERR " kobject: can not set name properly! \n " ) ;
return retval ;
}
kobj - > parent = parent ;
2007-12-18 09:05:35 +03:00
return kobject_add_internal ( kobj ) ;
2007-12-04 08:31:08 +03:00
}
/**
2007-12-18 09:05:35 +03:00
* kobject_add - the main kobject add function
2007-12-04 08:31:08 +03:00
* @ 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 associted 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 .
*
2007-12-19 03:40:42 +03:00
* Note , no " add " uevent will be created with this call , the caller should set
2007-12-04 08:31:08 +03:00
* 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 .
*/
2007-12-18 09:05:35 +03:00
int kobject_add ( struct kobject * kobj , struct kobject * parent ,
const char * fmt , . . . )
2007-12-04 08:31:08 +03:00
{
va_list args ;
int retval ;
if ( ! kobj )
return - EINVAL ;
2007-12-19 03:40:42 +03:00
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 ;
}
2007-12-04 08:31:08 +03:00
va_start ( args , fmt ) ;
retval = kobject_add_varg ( kobj , parent , fmt , args ) ;
va_end ( args ) ;
return retval ;
}
2007-12-18 09:05:35 +03:00
EXPORT_SYMBOL ( kobject_add ) ;
2007-12-04 08:31:08 +03:00
2007-12-04 08:31:08 +03:00
/**
* 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 .
*
2007-12-18 09:05:35 +03:00
* This function combines the call to kobject_init ( ) and
2007-12-18 09:05:35 +03:00
* kobject_add ( ) . The same type of error handling after a call to
* kobject_add ( ) and kobject lifetime rules are the same here .
2007-12-04 08:31:08 +03:00
*/
int kobject_init_and_add ( struct kobject * kobj , struct kobj_type * ktype ,
struct kobject * parent , const char * fmt , . . . )
{
va_list args ;
int retval ;
2007-12-18 09:05:35 +03:00
kobject_init ( kobj , ktype ) ;
2007-12-04 08:31:08 +03:00
va_start ( args , fmt ) ;
retval = kobject_add_varg ( kobj , parent , fmt , args ) ;
va_end ( args ) ;
return retval ;
}
EXPORT_SYMBOL_GPL ( kobject_init_and_add ) ;
2005-04-17 02:20:36 +04:00
/**
2008-01-25 08:59:04 +03:00
* kobject_rename - change the name of an object
* @ kobj : object in question .
* @ new_name : object ' s new name
2008-05-09 01:41:00 +04:00
*
* 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 .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
int kobject_rename ( struct kobject * kobj , const char * new_name )
2005-04-17 02:20:36 +04:00
{
int error = 0 ;
2007-03-07 21:49:30 +03:00
const char * devpath = NULL ;
2008-07-04 05:05:28 +04:00
const char * dup_name = NULL , * name ;
2007-03-07 21:49:30 +03:00
char * devpath_string = NULL ;
char * envp [ 2 ] ;
2005-04-17 02:20:36 +04:00
kobj = kobject_get ( kobj ) ;
if ( ! kobj )
return - EINVAL ;
2007-01-24 22:35:52 +03:00
if ( ! kobj - > parent )
return - EINVAL ;
2007-03-07 21:49:30 +03:00
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 ;
2008-07-04 05:05:28 +04:00
name = dup_name = kstrdup ( new_name , GFP_KERNEL ) ;
if ( ! name ) {
error = - ENOMEM ;
goto out ;
}
2007-07-31 14:15:08 +04:00
error = sysfs_rename_dir ( kobj , new_name ) ;
2008-07-04 05:05:28 +04:00
if ( error )
goto out ;
/* Install the new kobject name */
dup_name = kobj - > name ;
kobj - > name = name ;
2007-03-07 21:49:30 +03:00
/* 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 . */
2008-07-04 05:05:28 +04:00
kobject_uevent_env ( kobj , KOBJ_MOVE , envp ) ;
2007-03-07 21:49:30 +03:00
out :
2008-07-04 05:05:28 +04:00
kfree ( dup_name ) ;
2007-03-07 21:49:30 +03:00
kfree ( devpath_string ) ;
kfree ( devpath ) ;
2007-01-24 22:35:52 +03:00
kobject_put ( kobj ) ;
return error ;
}
2008-06-11 01:30:42 +04:00
EXPORT_SYMBOL_GPL ( kobject_rename ) ;
2007-01-24 22:35:52 +03:00
2006-11-20 19:07:51 +03:00
/**
2008-01-25 08:59:04 +03:00
* kobject_move - move object to another parent
* @ kobj : object in question .
* @ new_parent : object ' s new parent ( can be NULL )
2006-11-20 19:07:51 +03:00
*/
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 ) {
2007-01-08 22:16:44 +03:00
if ( kobj - > kset )
new_parent = kobject_get ( & kobj - > kset - > kobj ) ;
2006-11-20 19:07:51 +03:00
}
/* 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 ( kobj , new_parent ) ;
if ( error )
goto out ;
old_parent = kobj - > parent ;
kobj - > parent = new_parent ;
2007-03-03 16:11:21 +03:00
new_parent = NULL ;
2006-11-20 19:07:51 +03:00
kobject_put ( old_parent ) ;
kobject_uevent_env ( kobj , KOBJ_MOVE , envp ) ;
out :
2007-03-03 16:11:21 +03:00
kobject_put ( new_parent ) ;
2006-11-20 19:07:51 +03:00
kobject_put ( kobj ) ;
kfree ( devpath_string ) ;
kfree ( devpath ) ;
return error ;
}
2005-04-17 02:20:36 +04:00
/**
2008-01-25 08:59:04 +03:00
* kobject_del - unlink kobject from hierarchy .
* @ kobj : object .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
void kobject_del ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2007-01-18 23:23:51 +03:00
if ( ! kobj )
return ;
2007-12-19 03:40:42 +03:00
2005-04-17 02:20:36 +04:00
sysfs_remove_dir ( kobj ) ;
2007-12-19 03:40:42 +03:00
kobj - > state_in_sysfs = 0 ;
kobj_kset_leave ( kobj ) ;
kobject_put ( kobj - > parent ) ;
kobj - > parent = NULL ;
2005-04-17 02:20:36 +04:00
}
/**
2008-01-25 08:59:04 +03:00
* kobject_get - increment refcount for object .
* @ kobj : object .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
struct kobject * kobject_get ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
if ( kobj )
kref_get ( & kobj - > kref ) ;
return kobj ;
}
2013-05-08 02:37:48 +04:00
static struct kobject * __must_check kobject_get_unless_zero ( struct kobject * kobj )
2013-04-14 02:15:30 +04:00
{
if ( ! kref_get_unless_zero ( & kobj - > kref ) )
kobj = NULL ;
return kobj ;
}
2007-12-04 08:31:08 +03:00
/*
* kobject_cleanup - free kobject resources .
* @ kobj : object to cleanup
2005-04-17 02:20:36 +04:00
*/
2007-12-04 08:31:08 +03:00
static void kobject_cleanup ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2007-12-19 03:40:42 +03:00
struct kobj_type * t = get_ktype ( kobj ) ;
2007-12-20 04:09:39 +03:00
const char * name = kobj - > name ;
2005-04-17 02:20:36 +04:00
2013-06-27 18:06:14 +04:00
pr_debug ( " kobject: '%s' (%p): %s, parent %p \n " ,
kobject_name ( kobj ) , kobj , __func__ , kobj - > parent ) ;
2007-12-19 03:40:42 +03:00
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 ) ;
}
2007-09-13 02:06:57 +04:00
if ( t & & t - > release ) {
2007-12-19 03:40:42 +03:00
pr_debug ( " kobject: '%s' (%p): calling ktype release \n " ,
kobject_name ( kobj ) , kobj ) ;
2005-04-17 02:20:36 +04:00
t - > release ( kobj ) ;
2007-12-19 03:40:42 +03:00
}
/* free name if we allocated it */
2007-12-20 04:09:39 +03:00
if ( name ) {
2007-12-19 03:40:42 +03:00
pr_debug ( " kobject: '%s': free name \n " , name ) ;
2007-09-13 02:06:57 +04:00
kfree ( name ) ;
}
2005-04-17 02:20:36 +04:00
}
2013-06-27 18:06:14 +04: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 ) ) ;
}
# endif
2005-04-17 02:20:36 +04:00
static void kobject_release ( struct kref * kref )
{
2013-06-27 18:06:14 +04:00
struct kobject * kobj = container_of ( kref , struct kobject , kref ) ;
# ifdef CONFIG_DEBUG_KOBJECT_RELEASE
2013-10-09 05:26:21 +04:00
pr_info ( " kobject: '%s' (%p): %s, parent %p (delayed) \n " ,
2013-06-27 18:06:14 +04:00
kobject_name ( kobj ) , kobj , __func__ , kobj - > parent ) ;
INIT_DELAYED_WORK ( & kobj - > release , kobject_delayed_cleanup ) ;
schedule_delayed_work ( & kobj - > release , HZ ) ;
# else
kobject_cleanup ( kobj ) ;
# endif
2005-04-17 02:20:36 +04:00
}
/**
2008-01-25 08:59:04 +03:00
* kobject_put - decrement refcount for object .
* @ kobj : object .
2005-04-17 02:20:36 +04:00
*
2008-01-25 08:59:04 +03:00
* Decrement the refcount , and if 0 , call kobject_cleanup ( ) .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
void kobject_put ( struct kobject * kobj )
2005-04-17 02:20:36 +04:00
{
2008-02-26 20:36:38 +03:00
if ( kobj ) {
2008-07-25 12:45:55 +04:00
if ( ! kobj - > state_initialized )
WARN ( 1 , KERN_WARNING " kobject: '%s' (%p): is not "
2008-02-26 20:36:38 +03:00
" initialized, yet kobject_put() is being "
" called. \n " , kobject_name ( kobj ) , kobj ) ;
2005-04-17 02:20:36 +04:00
kref_put ( & kobj - > kref , kobject_release ) ;
2008-02-26 20:36:38 +03:00
}
2005-04-17 02:20:36 +04:00
}
2007-11-06 00:16:15 +03:00
static void dynamic_kobj_release ( struct kobject * kobj )
2006-03-14 01:14:25 +03:00
{
2008-04-30 11:55:08 +04:00
pr_debug ( " kobject: (%p): %s \n " , kobj , __func__ ) ;
2006-03-14 01:14:25 +03:00
kfree ( kobj ) ;
}
2007-11-06 00:16:15 +03:00
static struct kobj_type dynamic_kobj_ktype = {
2007-11-02 15:47:53 +03:00
. release = dynamic_kobj_release ,
. sysfs_ops = & kobj_sysfs_ops ,
2006-03-14 01:14:25 +03:00
} ;
2007-11-06 09:24:43 +03:00
/**
2007-11-06 00:16:15 +03:00
* 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 .
2007-11-06 09:24:43 +03:00
* The kobject structure returned from here must be cleaned up with a
2007-12-18 09:05:35 +03:00
* call to kobject_put ( ) and not kfree ( ) , as kobject_init ( ) has
2007-11-06 09:24:43 +03:00
* already been called on this structure .
2007-11-06 00:16:15 +03:00
*/
2007-11-06 09:24:43 +03:00
struct kobject * kobject_create ( void )
2007-11-06 00:16:15 +03:00
{
struct kobject * kobj ;
kobj = kzalloc ( sizeof ( * kobj ) , GFP_KERNEL ) ;
if ( ! kobj )
return NULL ;
2007-12-18 09:05:35 +03:00
kobject_init ( kobj , & dynamic_kobj_ktype ) ;
2007-11-06 00:16:15 +03:00
return kobj ;
}
/**
* kobject_create_and_add - create a struct kobject dynamically and register it with sysfs
*
2012-05-07 06:48:25 +04:00
* @ name : the name for the kobject
2007-11-06 00:16:15 +03:00
* @ parent : the parent kobject of this kobject , if any .
*
2008-01-28 11:58:00 +03:00
* This function creates a kobject structure dynamically and registers it
2007-11-06 00:16:15 +03:00
* with sysfs . When you are finished with this structure , call
2007-12-20 19:13:05 +03:00
* kobject_put ( ) and the structure will be dynamically freed when
2007-11-06 00:16:15 +03:00
* 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 ;
2007-12-18 09:05:35 +03:00
retval = kobject_add ( kobj , parent , " %s " , name ) ;
2007-11-06 00:16:15 +03:00
if ( retval ) {
printk ( KERN_WARNING " %s: kobject_add error: %d \n " ,
2008-04-30 11:55:08 +04:00
__func__ , retval ) ;
2007-11-06 00:16:15 +03:00
kobject_put ( kobj ) ;
kobj = NULL ;
}
return kobj ;
}
EXPORT_SYMBOL_GPL ( kobject_create_and_add ) ;
2005-04-17 02:20:36 +04:00
/**
2008-01-25 08:59:04 +03:00
* kset_init - initialize a kset for use
* @ k : kset
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
void kset_init ( struct kset * k )
2005-04-17 02:20:36 +04:00
{
2007-12-18 09:05:35 +03:00
kobject_init_internal ( & k - > kobj ) ;
2005-04-17 02:20:36 +04:00
INIT_LIST_HEAD ( & k - > list ) ;
spin_lock_init ( & k - > list_lock ) ;
}
2007-11-02 15:47:53 +03:00
/* default kobject attribute operations */
static ssize_t kobj_attr_show ( struct kobject * kobj , struct attribute * attr ,
char * buf )
{
struct kobj_attribute * kattr ;
ssize_t ret = - EIO ;
kattr = container_of ( attr , struct kobj_attribute , attr ) ;
if ( kattr - > show )
ret = kattr - > show ( kobj , kattr , buf ) ;
return ret ;
}
static ssize_t kobj_attr_store ( struct kobject * kobj , struct attribute * attr ,
const char * buf , size_t count )
{
struct kobj_attribute * kattr ;
ssize_t ret = - EIO ;
kattr = container_of ( attr , struct kobj_attribute , attr ) ;
if ( kattr - > store )
ret = kattr - > store ( kobj , kattr , buf , count ) ;
return ret ;
}
2010-01-19 04:58:23 +03:00
const struct sysfs_ops kobj_sysfs_ops = {
2007-11-02 15:47:53 +03:00
. show = kobj_attr_show ,
. store = kobj_attr_store ,
} ;
2005-04-17 02:20:36 +04:00
/**
2008-01-25 08:59:04 +03:00
* kset_register - initialize and add a kset .
* @ k : kset .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
int kset_register ( struct kset * k )
2005-04-17 02:20:36 +04:00
{
2007-05-26 13:21:36 +04:00
int err ;
2007-01-18 23:23:51 +03:00
if ( ! k )
return - EINVAL ;
2007-05-26 13:21:36 +04:00
2005-04-17 02:20:36 +04:00
kset_init ( k ) ;
2002-04-09 23:14:34 +04:00
err = kobject_add_internal ( & k - > kobj ) ;
2007-05-26 13:21:36 +04:00
if ( err )
return err ;
kobject_uevent ( & k - > kobj , KOBJ_ADD ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
/**
2008-01-25 08:59:04 +03:00
* kset_unregister - remove a kset .
* @ k : kset .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
void kset_unregister ( struct kset * k )
2005-04-17 02:20:36 +04:00
{
2007-01-18 23:23:51 +03:00
if ( ! k )
return ;
2007-12-20 19:13:05 +03:00
kobject_put ( & k - > kobj ) ;
2005-04-17 02:20:36 +04:00
}
/**
2008-01-25 08:59:04 +03:00
* kset_find_obj - search for object in kset .
* @ kset : kset we ' re looking in .
* @ name : object ' s name .
2005-04-17 02:20:36 +04:00
*
2008-01-25 08:59:04 +03:00
* 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 .
2005-04-17 02:20:36 +04:00
*/
2008-01-25 08:59:04 +03:00
struct kobject * kset_find_obj ( struct kset * kset , const char * name )
2005-04-17 02:20:36 +04:00
{
2008-03-27 08:13:34 +03:00
struct kobject * k ;
2008-01-25 08:59:04 +03:00
struct kobject * ret = NULL ;
2005-04-17 02:20:36 +04:00
spin_lock ( & kset - > list_lock ) ;
2010-09-29 23:00:54 +04:00
2008-03-27 08:13:34 +03:00
list_for_each_entry ( k , & kset - > list , entry ) {
2008-01-25 08:59:04 +03:00
if ( kobject_name ( k ) & & ! strcmp ( kobject_name ( k ) , name ) ) {
2013-04-14 02:15:30 +04:00
ret = kobject_get_unless_zero ( k ) ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2010-09-29 23:00:54 +04:00
2005-04-17 02:20:36 +04:00
spin_unlock ( & kset - > list_lock ) ;
return ret ;
}
2007-09-28 01:48:53 +04:00
static void kset_release ( struct kobject * kobj )
{
struct kset * kset = container_of ( kobj , struct kset , kobj ) ;
2007-11-29 10:49:41 +03:00
pr_debug ( " kobject: '%s' (%p): %s \n " ,
2008-04-30 11:55:08 +04:00
kobject_name ( kobj ) , kobj , __func__ ) ;
2007-09-28 01:48:53 +04:00
kfree ( kset ) ;
}
2007-11-02 15:47:53 +03:00
static struct kobj_type kset_ktype = {
. sysfs_ops = & kobj_sysfs_ops ,
2007-09-28 01:48:53 +04:00
. release = kset_release ,
} ;
/**
* kset_create - create a struct kset dynamically
*
* @ name : the name for the kset
* @ uevent_ops : a struct kset_uevent_ops for the kset
* @ parent_kobj : the parent kobject of this kset , if any .
*
* This function creates a kset structure dynamically . This structure can
* then be registered with the system and show up in sysfs with a call to
* kset_register ( ) . When you are finished with this structure , if
* kset_register ( ) has been called , call kset_unregister ( ) and the
* structure will be dynamically freed when it is no longer being used .
*
* If the kset was not able to be created , NULL will be returned .
*/
static struct kset * kset_create ( const char * name ,
2009-12-31 16:52:51 +03:00
const struct kset_uevent_ops * uevent_ops ,
2007-09-28 01:48:53 +04:00
struct kobject * parent_kobj )
{
struct kset * kset ;
2009-05-11 10:17:45 +04:00
int retval ;
2007-09-28 01:48:53 +04:00
kset = kzalloc ( sizeof ( * kset ) , GFP_KERNEL ) ;
if ( ! kset )
return NULL ;
2013-06-07 00:52:19 +04:00
retval = kobject_set_name ( & kset - > kobj , " %s " , name ) ;
2009-05-11 10:17:45 +04:00
if ( retval ) {
kfree ( kset ) ;
return NULL ;
}
2007-09-28 01:48:53 +04:00
kset - > uevent_ops = uevent_ops ;
kset - > kobj . parent = parent_kobj ;
/*
2007-11-02 15:47:53 +03:00
* The kobject of this kset will have a type of kset_ktype and belong to
2007-09-28 01:48:53 +04:00
* no kset itself . That way we can properly free it when it is
* finished being used .
*/
2007-11-02 15:47:53 +03:00
kset - > kobj . ktype = & kset_ktype ;
2007-09-28 01:48:53 +04:00
kset - > kobj . kset = NULL ;
return kset ;
}
/**
* kset_create_and_add - create a struct kset dynamically and add it to sysfs
*
* @ name : the name for the kset
* @ uevent_ops : a struct kset_uevent_ops for the kset
* @ parent_kobj : the parent kobject of this kset , if any .
*
* This function creates a kset structure dynamically and registers it
* with sysfs . When you are finished with this structure , call
* kset_unregister ( ) and the structure will be dynamically freed when it
* is no longer being used .
*
* If the kset was not able to be created , NULL will be returned .
*/
struct kset * kset_create_and_add ( const char * name ,
2009-12-31 16:52:51 +03:00
const struct kset_uevent_ops * uevent_ops ,
2007-09-28 01:48:53 +04:00
struct kobject * parent_kobj )
{
struct kset * kset ;
int error ;
kset = kset_create ( name , uevent_ops , parent_kobj ) ;
if ( ! kset )
return NULL ;
error = kset_register ( kset ) ;
if ( error ) {
kfree ( kset ) ;
return NULL ;
}
return kset ;
}
EXPORT_SYMBOL_GPL ( kset_create_and_add ) ;
2010-03-30 22:31:25 +04:00
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 ) ;
}
2013-03-26 07:07:01 +04:00
bool kobj_ns_current_may_mount ( enum kobj_ns_type type )
{
2013-09-24 01:41:17 +04:00
bool may_mount = true ;
2013-03-26 07:07:01 +04:00
spin_lock ( & kobj_ns_type_lock ) ;
if ( ( type > KOBJ_NS_TYPE_NONE ) & & ( type < KOBJ_NS_TYPES ) & &
kobj_ns_ops_tbl [ type ] )
may_mount = kobj_ns_ops_tbl [ type ] - > current_may_mount ( ) ;
spin_unlock ( & kobj_ns_type_lock ) ;
return may_mount ;
}
2010-03-30 22:31:25 +04:00
2011-06-09 05:13:01 +04:00
void * kobj_ns_grab_current ( enum kobj_ns_type type )
2010-03-30 22:31:25 +04:00
{
2011-06-09 05:13:01 +04:00
void * ns = NULL ;
2010-03-30 22:31:25 +04:00
spin_lock ( & kobj_ns_type_lock ) ;
if ( ( type > KOBJ_NS_TYPE_NONE ) & & ( type < KOBJ_NS_TYPES ) & &
kobj_ns_ops_tbl [ type ] )
2011-06-09 05:13:01 +04:00
ns = kobj_ns_ops_tbl [ type ] - > grab_current_ns ( ) ;
2010-03-30 22:31:25 +04:00
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 ;
}
2011-06-09 05:13:01 +04:00
void kobj_ns_drop ( enum kobj_ns_type type , void * ns )
2010-03-30 22:31:25 +04:00
{
2011-06-09 05:13:01 +04:00
spin_lock ( & kobj_ns_type_lock ) ;
if ( ( type > KOBJ_NS_TYPE_NONE ) & & ( type < KOBJ_NS_TYPES ) & &
kobj_ns_ops_tbl [ type ] & & kobj_ns_ops_tbl [ type ] - > drop_ns )
kobj_ns_ops_tbl [ type ] - > drop_ns ( ns ) ;
spin_unlock ( & kobj_ns_type_lock ) ;
2010-03-30 22:31:25 +04:00
}
2005-04-17 02:20:36 +04:00
EXPORT_SYMBOL ( kobject_get ) ;
EXPORT_SYMBOL ( kobject_put ) ;
EXPORT_SYMBOL ( kobject_del ) ;
EXPORT_SYMBOL ( kset_register ) ;
EXPORT_SYMBOL ( kset_unregister ) ;