2005-04-16 15:20:36 -07:00
/*
2007-09-20 17:31:38 +09:00
* fs / sysfs / dir . c - sysfs core and dir operation implementation
*
* Copyright ( c ) 2001 - 3 Patrick Mochel
* Copyright ( c ) 2007 SUSE Linux Products GmbH
* Copyright ( c ) 2007 Tejun Heo < teheo @ suse . de >
*
* This file is released under the GPLv2 .
*
* Please see Documentation / filesystems / sysfs . txt for more information .
2005-04-16 15:20:36 -07:00
*/
# undef DEBUG
# include <linux/fs.h>
# include <linux/kobject.h>
2008-03-13 22:41:52 -04:00
# include <linux/slab.h>
2005-04-16 15:20:36 -07:00
# include "sysfs.h"
2013-10-30 10:28:36 -04:00
DEFINE_SPINLOCK ( sysfs_symlink_target_lock ) ;
2005-04-16 15:20:36 -07:00
2009-02-12 10:56:59 -07:00
/**
* sysfs_pathname - return full path to sysfs dirent
2013-12-11 14:11:53 -05:00
* @ kn : kernfs_node whose path we want
2012-09-29 22:23:19 +02:00
* @ path : caller allocated buffer of size PATH_MAX
2009-02-12 10:56:59 -07:00
*
* Gives the name " / " to the sysfs_root entry ; any path returned
* is relative to wherever sysfs is mounted .
*/
2013-12-11 14:11:53 -05:00
static char * sysfs_pathname ( struct kernfs_node * kn , char * path )
2009-02-12 10:56:59 -07:00
{
2013-12-11 14:11:54 -05:00
if ( kn - > parent ) {
sysfs_pathname ( kn - > parent , path ) ;
2012-09-29 22:23:19 +02:00
strlcat ( path , " / " , PATH_MAX ) ;
2009-02-12 10:56:59 -07:00
}
2013-12-11 14:11:54 -05:00
strlcat ( path , kn - > name , PATH_MAX ) ;
2009-02-12 10:56:59 -07:00
return path ;
}
2013-12-11 14:11:53 -05:00
void sysfs_warn_dup ( struct kernfs_node * parent , const char * name )
2013-10-24 11:49:11 -04:00
{
char * path ;
path = kzalloc ( PATH_MAX , GFP_KERNEL ) ;
if ( path ) {
sysfs_pathname ( parent , path ) ;
strlcat ( path , " / " , PATH_MAX ) ;
strlcat ( path , name , PATH_MAX ) ;
}
WARN ( 1 , KERN_WARNING " sysfs: cannot create duplicate filename '%s' \n " ,
path ? path : name ) ;
kfree ( path ) ;
}
2005-04-16 15:20:36 -07:00
/**
2013-09-11 22:29:05 -04:00
* sysfs_create_dir_ns - create a directory for an object with a namespace tag
* @ kobj : object we ' re creating directory for
* @ ns : the namespace tag to use
2005-04-16 15:20:36 -07:00
*/
2013-09-11 22:29:05 -04:00
int sysfs_create_dir_ns ( struct kobject * kobj , const void * ns )
2005-04-16 15:20:36 -07:00
{
2013-12-11 14:11:53 -05:00
struct kernfs_node * parent , * kn ;
2005-04-16 15:20:36 -07:00
BUG_ON ( ! kobj ) ;
2007-07-31 19:15:08 +09:00
if ( kobj - > parent )
2013-12-11 14:11:53 -05:00
parent = kobj - > parent - > sd ;
2005-04-16 15:20:36 -07:00
else
2013-12-11 14:11:53 -05:00
parent = sysfs_root_kn ;
2005-04-16 15:20:36 -07:00
2013-12-11 14:11:53 -05:00
if ( ! parent )
2012-04-06 13:41:06 -07:00
return - ENOENT ;
2013-12-11 16:02:55 -05:00
kn = kernfs_create_dir_ns ( parent , kobject_name ( kobj ) ,
S_IRWXU | S_IRUGO | S_IXUGO , kobj , ns ) ;
2013-12-11 14:11:53 -05:00
if ( IS_ERR ( kn ) ) {
if ( PTR_ERR ( kn ) = = - EEXIST )
sysfs_warn_dup ( parent , kobject_name ( kobj ) ) ;
return PTR_ERR ( kn ) ;
2013-11-28 14:54:15 -05:00
}
2013-12-11 14:11:53 -05:00
kobj - > sd = kn ;
2013-11-28 14:54:15 -05:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2007-01-24 12:35:52 -07:00
/**
* sysfs_remove_dir - remove an object ' s directory .
* @ kobj : object .
*
* The only thing special about this is that we remove any files in
* the directory before we remove the directory , and we ' ve inlined
* what used to be sysfs_rmdir ( ) below , instead of calling separately .
*/
2013-08-21 16:28:26 -07:00
void sysfs_remove_dir ( struct kobject * kobj )
2007-01-24 12:35:52 -07:00
{
2013-12-11 14:11:53 -05:00
struct kernfs_node * kn = kobj - > sd ;
2007-06-14 03:45:15 +09:00
2013-10-30 10:28:36 -04:00
/*
* In general , kboject owner is responsible for ensuring removal
* doesn ' t race with other operations and sysfs doesn ' t provide any
* protection ; however , when @ kobj is used as a symlink target , the
* symlinking entity usually doesn ' t own @ kobj and thus has no
2013-12-11 14:11:53 -05:00
* control over removal . @ kobj - > sd may be removed anytime
* and symlink code may end up dereferencing an already freed node .
2013-10-30 10:28:36 -04:00
*
2013-12-11 14:11:53 -05:00
* sysfs_symlink_target_lock synchronizes @ kobj - > sd
* disassociation against symlink operations so that symlink code
* can safely dereference @ kobj - > sd .
2013-10-30 10:28:36 -04:00
*/
spin_lock ( & sysfs_symlink_target_lock ) ;
2007-06-14 04:27:22 +09:00
kobj - > sd = NULL ;
2013-10-30 10:28:36 -04:00
spin_unlock ( & sysfs_symlink_target_lock ) ;
2007-06-14 03:45:15 +09:00
2013-12-11 14:11:53 -05:00
if ( kn ) {
2013-12-11 14:11:56 -05:00
WARN_ON_ONCE ( kernfs_type ( kn ) ! = KERNFS_DIR ) ;
2013-12-11 14:11:53 -05:00
kernfs_remove ( kn ) ;
2013-09-18 17:15:38 -04:00
}
2005-04-16 15:20:36 -07:00
}
2013-09-11 22:29:05 -04:00
int sysfs_rename_dir_ns ( struct kobject * kobj , const char * new_name ,
const void * new_ns )
2009-11-20 16:08:57 -08:00
{
2013-12-11 14:11:54 -05:00
struct kernfs_node * parent = kobj - > sd - > parent ;
2010-03-30 11:31:26 -07:00
2013-12-11 14:11:53 -05:00
return kernfs_rename_ns ( kobj - > sd , parent , new_name , new_ns ) ;
2009-11-20 16:08:57 -08:00
}
2013-09-11 22:29:05 -04:00
int sysfs_move_dir_ns ( struct kobject * kobj , struct kobject * new_parent_kobj ,
const void * new_ns )
2006-11-20 17:07:51 +01:00
{
2013-12-11 14:11:53 -05:00
struct kernfs_node * kn = kobj - > sd ;
struct kernfs_node * new_parent ;
2006-11-20 17:07:51 +01:00
2013-12-11 14:11:54 -05:00
BUG_ON ( ! kn - > parent ) ;
2013-12-11 14:11:53 -05:00
new_parent = new_parent_kobj & & new_parent_kobj - > sd ?
new_parent_kobj - > sd : sysfs_root_kn ;
2007-06-14 04:27:25 +09:00
2013-12-11 14:11:54 -05:00
return kernfs_rename_ns ( kn , new_parent , kn - > name , new_ns ) ;
2006-11-20 17:07:51 +01:00
}