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 / symlink . c - sysfs symlink 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
*/
# include <linux/fs.h>
# include <linux/module.h>
# include <linux/kobject.h>
2007-07-26 18:53:53 +04:00
# include <linux/mutex.h>
2009-09-09 22:25:37 +04:00
# include <linux/security.h>
2005-04-17 02:20:36 +04:00
# include "sysfs.h"
2013-12-11 23:11:53 +04:00
static int sysfs_do_create_link_sd ( struct kernfs_node * parent ,
struct kobject * target_kobj ,
2013-01-26 00:51:13 +04:00
const char * name , int warn )
2005-04-17 02:20:36 +04:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * kn , * target = NULL ;
2005-04-17 02:20:36 +04:00
2019-01-03 12:23:47 +03:00
if ( WARN_ON ( ! name | | ! parent ) )
return - EINVAL ;
2007-06-13 22:45:15 +04:00
2013-10-30 18:28:36 +04:00
/*
2013-12-11 23:11:53 +04:00
* We don ' t own @ target_kobj and it may be removed at any time .
2013-10-30 18:28:36 +04:00
* Synchronize using sysfs_symlink_target_lock . See
* sysfs_remove_dir ( ) for details .
2007-06-13 22:45:15 +04:00
*/
2013-10-30 18:28:36 +04:00
spin_lock ( & sysfs_symlink_target_lock ) ;
2013-12-11 23:11:53 +04:00
if ( target_kobj - > sd ) {
target = target_kobj - > sd ;
kernfs_get ( target ) ;
2013-11-28 23:54:30 +04:00
}
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 ( ! target )
2013-11-24 02:21:50 +04:00
return - ENOENT ;
2007-07-18 11:14:45 +04:00
2013-12-11 23:11:53 +04:00
kn = kernfs_create_link ( parent , name , target ) ;
kernfs_put ( target ) ;
2007-07-18 11:38:11 +04:00
2013-12-11 23:11:53 +04:00
if ( ! IS_ERR ( kn ) )
2013-11-24 02:21:50 +04:00
return 0 ;
2007-06-13 23:27:24 +04:00
2013-12-11 23:11:53 +04:00
if ( warn & & PTR_ERR ( kn ) = = - EEXIST )
sysfs_warn_dup ( parent , name ) ;
return PTR_ERR ( kn ) ;
2005-04-17 02:20:36 +04:00
}
2013-01-26 00:51:13 +04:00
/**
* sysfs_create_link_sd - create symlink to a given object .
2013-12-11 23:11:53 +04:00
* @ kn : directory we ' re creating the link in .
2013-01-26 00:51:13 +04:00
* @ target : object we ' re pointing to .
* @ name : name of the symlink .
*/
2013-12-11 23:11:53 +04:00
int sysfs_create_link_sd ( struct kernfs_node * kn , struct kobject * target ,
2013-01-26 00:51:13 +04:00
const char * name )
{
2013-12-11 23:11:53 +04:00
return sysfs_do_create_link_sd ( kn , target , name , 1 ) ;
2013-01-26 00:51:13 +04:00
}
static int sysfs_do_create_link ( struct kobject * kobj , struct kobject * target ,
const char * name , int warn )
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * parent = NULL ;
2013-01-26 00:51:13 +04:00
if ( ! kobj )
2013-12-11 23:11:53 +04:00
parent = sysfs_root_kn ;
2013-01-26 00:51:13 +04:00
else
2013-12-11 23:11:53 +04:00
parent = kobj - > sd ;
2013-01-26 00:51:13 +04:00
2013-12-11 23:11:53 +04:00
if ( ! parent )
2013-01-26 00:51:13 +04:00
return - EFAULT ;
2013-12-11 23:11:53 +04:00
return sysfs_do_create_link_sd ( parent , target , name , warn ) ;
2013-01-26 00:51:13 +04:00
}
2008-06-10 13:09:08 +04:00
/**
* sysfs_create_link - create symlink between two objects .
* @ kobj : object whose directory we ' re creating the link in .
* @ target : object we ' re pointing to .
* @ name : name of the symlink .
*/
int sysfs_create_link ( struct kobject * kobj , struct kobject * target ,
const char * name )
{
return sysfs_do_create_link ( kobj , target , name , 1 ) ;
}
2013-08-22 03:17:47 +04:00
EXPORT_SYMBOL_GPL ( sysfs_create_link ) ;
2008-06-10 13:09:08 +04:00
/**
* sysfs_create_link_nowarn - create symlink between two objects .
* @ kobj : object whose directory we ' re creating the link in .
* @ target : object we ' re pointing to .
* @ name : name of the symlink .
*
2012-09-04 15:23:35 +04:00
* This function does the same as sysfs_create_link ( ) , but it
2008-06-10 13:09:08 +04:00
* doesn ' t warn if the link already exists .
*/
int sysfs_create_link_nowarn ( struct kobject * kobj , struct kobject * target ,
const char * name )
{
return sysfs_do_create_link ( kobj , target , name , 0 ) ;
}
2018-03-17 01:08:34 +03:00
EXPORT_SYMBOL_GPL ( sysfs_create_link_nowarn ) ;
2008-06-10 13:09:08 +04:00
2010-03-30 22:31:28 +04:00
/**
* sysfs_delete_link - remove symlink in object ' s directory .
* @ kobj : object we ' re acting for .
* @ targ : object we ' re pointing to .
* @ name : name of the symlink to remove .
*
* Unlike sysfs_remove_link sysfs_delete_link has enough information
* to successfully delete symlinks in tagged directories .
*/
void sysfs_delete_link ( struct kobject * kobj , struct kobject * targ ,
const char * name )
{
const void * ns = NULL ;
2013-10-30 18:28:36 +04:00
/*
* We don ' t own @ target and it may be removed at any time .
* Synchronize using sysfs_symlink_target_lock . See
* sysfs_remove_dir ( ) for details .
*/
spin_lock ( & sysfs_symlink_target_lock ) ;
2013-11-30 02:19:09 +04:00
if ( targ - > sd & & kernfs_ns_enabled ( kobj - > sd ) )
2013-12-11 23:11:54 +04:00
ns = targ - > sd - > ns ;
2013-10-30 18:28:36 +04:00
spin_unlock ( & sysfs_symlink_target_lock ) ;
2013-11-24 02:21:49 +04:00
kernfs_remove_by_name_ns ( kobj - > sd , name , ns ) ;
2010-03-30 22:31:28 +04:00
}
2005-04-17 02:20:36 +04:00
/**
* sysfs_remove_link - remove symlink in object ' s directory .
* @ kobj : object we ' re acting for .
* @ name : name of the symlink to remove .
*/
2013-08-22 03:28:26 +04:00
void sysfs_remove_link ( struct kobject * kobj , const char * name )
2005-04-17 02:20:36 +04:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * parent = NULL ;
2008-01-30 01:35:18 +03:00
if ( ! kobj )
2013-12-11 23:11:53 +04:00
parent = sysfs_root_kn ;
2008-01-30 01:35:18 +03:00
else
2013-12-11 23:11:53 +04:00
parent = kobj - > sd ;
2008-01-30 01:35:18 +03:00
2013-12-11 23:11:53 +04:00
kernfs_remove_by_name ( parent , name ) ;
2005-04-17 02:20:36 +04:00
}
2013-08-22 03:17:47 +04:00
EXPORT_SYMBOL_GPL ( sysfs_remove_link ) ;
2005-04-17 02:20:36 +04:00
2010-02-13 06:22:25 +03:00
/**
2013-09-12 06:29:06 +04:00
* sysfs_rename_link_ns - rename symlink in object ' s directory .
2010-02-13 06:22:25 +03:00
* @ kobj : object we ' re acting for .
* @ targ : object we ' re pointing to .
* @ old : previous name of the symlink .
* @ new : new name of the symlink .
2013-09-12 06:29:06 +04:00
* @ new_ns : new namespace of the symlink .
2010-02-13 06:22:25 +03:00
*
* A helper function for the common rename symlink idiom .
*/
2013-09-12 06:29:06 +04:00
int sysfs_rename_link_ns ( struct kobject * kobj , struct kobject * targ ,
const char * old , const char * new , const void * new_ns )
2010-02-13 06:22:25 +03:00
{
2013-12-11 23:11:53 +04:00
struct kernfs_node * parent , * kn = NULL ;
2013-09-12 06:29:06 +04:00
const void * old_ns = NULL ;
2010-02-13 06:22:25 +03:00
int result ;
if ( ! kobj )
2013-12-11 23:11:53 +04:00
parent = sysfs_root_kn ;
2010-02-13 06:22:25 +03:00
else
2013-12-11 23:11:53 +04:00
parent = kobj - > sd ;
2010-02-13 06:22:25 +03:00
2010-03-30 22:31:26 +04:00
if ( targ - > sd )
2013-12-11 23:11:54 +04:00
old_ns = targ - > sd - > ns ;
2010-03-30 22:31:26 +04:00
2010-02-13 06:22:25 +03:00
result = - ENOENT ;
2013-12-11 23:11:53 +04:00
kn = kernfs_find_and_get_ns ( parent , old , old_ns ) ;
if ( ! kn )
2010-02-13 06:22:25 +03:00
goto out ;
result = - EINVAL ;
2013-12-11 23:11:56 +04:00
if ( kernfs_type ( kn ) ! = KERNFS_LINK )
2010-02-13 06:22:25 +03:00
goto out ;
2013-12-11 23:11:54 +04:00
if ( kn - > symlink . target_kn - > priv ! = targ )
2010-02-13 06:22:25 +03:00
goto out ;
2013-12-11 23:11:53 +04:00
result = kernfs_rename_ns ( kn , parent , new , new_ns ) ;
2010-02-13 06:22:25 +03:00
out :
2013-12-11 23:11:53 +04:00
kernfs_put ( kn ) ;
2010-02-13 06:22:25 +03:00
return result ;
}
2013-09-12 06:29:06 +04:00
EXPORT_SYMBOL_GPL ( sysfs_rename_link_ns ) ;