2018-01-22 18:18:13 +03:00
// SPDX-License-Identifier: GPL-2.0
2005-04-17 02:20:36 +04:00
/*
2007-09-20 12:31:38 +04: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 19:48:37 +03:00
* Please see Documentation / filesystems / sysfs . rst for more information .
2005-04-17 02:20:36 +04:00
*/
2018-01-22 17:57:59 +03:00
# define pr_fmt(fmt) "sysfs: " fmt
2005-04-17 02:20:36 +04:00
# include <linux/fs.h>
# include <linux/kobject.h>
2008-03-14 05:41:52 +03:00
# include <linux/slab.h>
2005-04-17 02:20:36 +04:00
# include "sysfs.h"
2013-10-30 18:28:36 +04:00
DEFINE_SPINLOCK ( sysfs_symlink_target_lock ) ;
2005-04-17 02:20:36 +04:00
2013-12-11 23:11:53 +04:00
void sysfs_warn_dup ( struct kernfs_node * parent , const char * name )
2013-10-24 19:49:11 +04:00
{
2016-08-10 18:23:44 +03:00
char * buf ;
2013-10-24 19:49:11 +04:00
2014-02-07 22:32:07 +04:00
buf = kzalloc ( PATH_MAX , GFP_KERNEL ) ;
if ( buf )
2016-08-10 18:23:44 +03:00
kernfs_path ( parent , buf , PATH_MAX ) ;
2013-10-24 19:49:11 +04:00
2018-01-22 17:57:59 +03:00
pr_warn ( " cannot create duplicate filename '%s/%s' \n " , buf , name ) ;
dump_stack ( ) ;
2013-10-24 19:49:11 +04:00
2014-02-07 22:32:07 +04:00
kfree ( buf ) ;
2013-10-24 19:49:11 +04:00
}
2005-04-17 02:20:36 +04:00
/**
2013-09-12 06: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-17 02:20:36 +04:00
*/
2013-09-12 06:29:05 +04:00
int sysfs_create_dir_ns ( struct kobject * kobj , const void * ns )
2005-04-17 02:20:36 +04:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * parent , * kn ;
2018-07-21 00:56:48 +03:00
kuid_t uid ;
kgid_t gid ;
2005-04-17 02:20:36 +04:00
2019-01-03 12:23:47 +03:00
if ( WARN_ON ( ! kobj ) )
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2007-07-31 14:15:08 +04:00
if ( kobj - > parent )
2013-12-11 23:11:53 +04:00
parent = kobj - > parent - > sd ;
2005-04-17 02:20:36 +04:00
else
2013-12-11 23:11:53 +04:00
parent = sysfs_root_kn ;
2005-04-17 02:20:36 +04:00
2013-12-11 23:11:53 +04:00
if ( ! parent )
2012-04-07 00:41:06 +04:00
return - ENOENT ;
2018-07-21 00:56:48 +03:00
kobject_get_ownership ( kobj , & uid , & gid ) ;
2021-09-27 19:38:01 +03:00
kn = kernfs_create_dir_ns ( parent , kobject_name ( kobj ) , 0755 , uid , gid ,
2018-07-21 00:56:47 +03:00
kobj , ns ) ;
2013-12-11 23:11:53 +04:00
if ( IS_ERR ( kn ) ) {
if ( PTR_ERR ( kn ) = = - EEXIST )
sysfs_warn_dup ( parent , kobject_name ( kobj ) ) ;
return PTR_ERR ( kn ) ;
2013-11-28 23:54:15 +04:00
}
2013-12-11 23:11:53 +04:00
kobj - > sd = kn ;
2013-11-28 23:54:15 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2007-01-24 22:35:52 +03: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-22 03:28:26 +04:00
void sysfs_remove_dir ( struct kobject * kobj )
2007-01-24 22:35:52 +03:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * kn = kobj - > sd ;
2007-06-13 22:45:15 +04:00
2013-10-30 18: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 23:11:53 +04:00
* control over removal . @ kobj - > sd may be removed anytime
* and symlink code may end up dereferencing an already freed node .
2013-10-30 18:28:36 +04:00
*
2013-12-11 23:11:53 +04:00
* sysfs_symlink_target_lock synchronizes @ kobj - > sd
* disassociation against symlink operations so that symlink code
* can safely dereference @ kobj - > sd .
2013-10-30 18:28:36 +04:00
*/
spin_lock ( & sysfs_symlink_target_lock ) ;
2007-06-13 23:27:22 +04:00
kobj - > sd = NULL ;
2013-10-30 18:28:36 +04:00
spin_unlock ( & sysfs_symlink_target_lock ) ;
2007-06-13 22:45:15 +04:00
2013-12-11 23:11:53 +04:00
if ( kn ) {
2013-12-11 23:11:56 +04:00
WARN_ON_ONCE ( kernfs_type ( kn ) ! = KERNFS_DIR ) ;
2013-12-11 23:11:53 +04:00
kernfs_remove ( kn ) ;
2013-09-19 01:15:38 +04:00
}
2005-04-17 02:20:36 +04:00
}
2013-09-12 06:29:05 +04:00
int sysfs_rename_dir_ns ( struct kobject * kobj , const char * new_name ,
const void * new_ns )
2009-11-21 03:08:57 +03:00
{
2014-02-07 22:32:07 +04:00
struct kernfs_node * parent ;
int ret ;
2010-03-30 22:31:26 +04:00
2014-02-07 22:32:07 +04: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-21 03:08:57 +03:00
}
2013-09-12 06:29:05 +04:00
int sysfs_move_dir_ns ( struct kobject * kobj , struct kobject * new_parent_kobj ,
const void * new_ns )
2006-11-20 19:07:51 +03:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * kn = kobj - > sd ;
struct kernfs_node * new_parent ;
2006-11-20 19:07:51 +03:00
2013-12-11 23:11:53 +04:00
new_parent = new_parent_kobj & & new_parent_kobj - > sd ?
new_parent_kobj - > sd : sysfs_root_kn ;
2007-06-13 23:27:25 +04:00
2013-12-11 23:11:54 +04:00
return kernfs_rename_ns ( kn , new_parent , kn - > name , new_ns ) ;
2006-11-20 19:07:51 +03:00
}
2015-05-14 00:31:40 +03: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 ) ;