2018-01-22 16:18:13 +01:00
// SPDX-License-Identifier: GPL-2.0
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 >
*
2020-04-14 18:48:37 +02:00
* Please see Documentation / filesystems / sysfs . rst for more information .
2005-04-16 15:20:36 -07:00
*/
2018-01-22 15:57:59 +01:00
# define pr_fmt(fmt) "sysfs: " fmt
2005-04-16 15:20:36 -07:00
# 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
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
{
2016-08-10 11:23:44 -04:00
char * buf ;
2013-10-24 11:49:11 -04:00
2014-02-07 13:32:07 -05:00
buf = kzalloc ( PATH_MAX , GFP_KERNEL ) ;
if ( buf )
2016-08-10 11:23:44 -04:00
kernfs_path ( parent , buf , PATH_MAX ) ;
2013-10-24 11:49:11 -04:00
2018-01-22 15:57:59 +01:00
pr_warn ( " cannot create duplicate filename '%s/%s' \n " , buf , name ) ;
dump_stack ( ) ;
2013-10-24 11:49:11 -04:00
2014-02-07 13:32:07 -05:00
kfree ( buf ) ;
2013-10-24 11:49:11 -04:00
}
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 ;
2018-07-20 21:56:48 +00:00
kuid_t uid ;
kgid_t gid ;
2005-04-16 15:20:36 -07:00
2019-01-03 10:23:47 +01:00
if ( WARN_ON ( ! kobj ) )
return - EINVAL ;
2005-04-16 15:20:36 -07:00
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 ;
2018-07-20 21:56:48 +00:00
kobject_get_ownership ( kobj , & uid , & gid ) ;
2013-12-11 16:02:55 -05:00
kn = kernfs_create_dir_ns ( parent , kobject_name ( kobj ) ,
2018-07-20 21:56:48 +00:00
S_IRWXU | S_IRUGO | S_IXUGO , uid , gid ,
2018-07-20 21:56:47 +00:00
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
{
2014-02-07 13:32:07 -05:00
struct kernfs_node * parent ;
int ret ;
2010-03-30 11:31:26 -07:00
2014-02-07 13:32:07 -05:00
parent = kernfs_get_parent ( kobj - > sd ) ;
ret = kernfs_rename_ns ( kobj - > sd , parent , new_name , new_ns ) ;
kernfs_put ( parent ) ;
return ret ;
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: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
}
2015-05-13 16:31:40 -05:00
/**
* sysfs_create_mount_point - create an always empty directory
* @ parent_kobj : kobject that will contain this always empty directory
* @ name : The name of the always empty directory to add
*/
int sysfs_create_mount_point ( struct kobject * parent_kobj , const char * name )
{
struct kernfs_node * kn , * parent = parent_kobj - > sd ;
kn = kernfs_create_empty_dir ( parent , name ) ;
if ( IS_ERR ( kn ) ) {
if ( PTR_ERR ( kn ) = = - EEXIST )
sysfs_warn_dup ( parent , name ) ;
return PTR_ERR ( kn ) ;
}
return 0 ;
}
EXPORT_SYMBOL_GPL ( sysfs_create_mount_point ) ;
/**
* sysfs_remove_mount_point - remove an always empty directory .
* @ parent_kobj : kobject that will contain this always empty directory
* @ name : The name of the always empty directory to remove
*
*/
void sysfs_remove_mount_point ( struct kobject * parent_kobj , const char * name )
{
struct kernfs_node * parent = parent_kobj - > sd ;
kernfs_remove_by_name_ns ( parent , name , NULL ) ;
}
EXPORT_SYMBOL_GPL ( sysfs_remove_mount_point ) ;