xref: /openbmc/linux/fs/sysfs/symlink.c (revision 0c1bc6b8)
1619daeeeSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
36d66f5cdSTejun Heo  * fs/sysfs/symlink.c - sysfs symlink implementation
46d66f5cdSTejun Heo  *
56d66f5cdSTejun Heo  * Copyright (c) 2001-3 Patrick Mochel
66d66f5cdSTejun Heo  * Copyright (c) 2007 SUSE Linux Products GmbH
76d66f5cdSTejun Heo  * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
86d66f5cdSTejun Heo  *
90c1bc6b8SMauro Carvalho Chehab  * Please see Documentation/filesystems/sysfs.rst for more information.
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
121da177e4SLinus Torvalds #include <linux/fs.h>
131da177e4SLinus Torvalds #include <linux/module.h>
141da177e4SLinus Torvalds #include <linux/kobject.h>
15869512abSDave Young #include <linux/mutex.h>
16ddd29ec6SDavid P. Quigley #include <linux/security.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include "sysfs.h"
191da177e4SLinus Torvalds 
sysfs_do_create_link_sd(struct kernfs_node * parent,struct kobject * target_kobj,const char * name,int warn)20324a56e1STejun Heo static int sysfs_do_create_link_sd(struct kernfs_node *parent,
21324a56e1STejun Heo 				   struct kobject *target_kobj,
2236ce6dadSCornelia Huck 				   const char *name, int warn)
231da177e4SLinus Torvalds {
24324a56e1STejun Heo 	struct kernfs_node *kn, *target = NULL;
251da177e4SLinus Torvalds 
26de96e9feSGreg Kroah-Hartman 	if (WARN_ON(!name || !parent))
27de96e9feSGreg Kroah-Hartman 		return -EINVAL;
282b29ac25STejun Heo 
290cae60f9STejun Heo 	/*
30324a56e1STejun Heo 	 * We don't own @target_kobj and it may be removed at any time.
310cae60f9STejun Heo 	 * Synchronize using sysfs_symlink_target_lock.  See
320cae60f9STejun Heo 	 * sysfs_remove_dir() for details.
332b29ac25STejun Heo 	 */
340cae60f9STejun Heo 	spin_lock(&sysfs_symlink_target_lock);
35324a56e1STejun Heo 	if (target_kobj->sd) {
36324a56e1STejun Heo 		target = target_kobj->sd;
37324a56e1STejun Heo 		kernfs_get(target);
38ccf73cf3STejun Heo 	}
390cae60f9STejun Heo 	spin_unlock(&sysfs_symlink_target_lock);
402b29ac25STejun Heo 
41324a56e1STejun Heo 	if (!target)
425d0e26bbSTejun Heo 		return -ENOENT;
431da177e4SLinus Torvalds 
44324a56e1STejun Heo 	kn = kernfs_create_link(parent, name, target);
45324a56e1STejun Heo 	kernfs_put(target);
46a1da4dfeSTejun Heo 
47324a56e1STejun Heo 	if (!IS_ERR(kn))
483007e997STejun Heo 		return 0;
493007e997STejun Heo 
50324a56e1STejun Heo 	if (warn && PTR_ERR(kn) == -EEXIST)
51324a56e1STejun Heo 		sysfs_warn_dup(parent, name);
52324a56e1STejun Heo 	return PTR_ERR(kn);
531da177e4SLinus Torvalds }
541da177e4SLinus Torvalds 
551da177e4SLinus Torvalds /**
560bb8f3d6SRafael J. Wysocki  *	sysfs_create_link_sd - create symlink to a given object.
57324a56e1STejun Heo  *	@kn:		directory we're creating the link in.
580bb8f3d6SRafael J. Wysocki  *	@target:	object we're pointing to.
590bb8f3d6SRafael J. Wysocki  *	@name:		name of the symlink.
600bb8f3d6SRafael J. Wysocki  */
sysfs_create_link_sd(struct kernfs_node * kn,struct kobject * target,const char * name)61324a56e1STejun Heo int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target,
620bb8f3d6SRafael J. Wysocki 			 const char *name)
630bb8f3d6SRafael J. Wysocki {
64324a56e1STejun Heo 	return sysfs_do_create_link_sd(kn, target, name, 1);
650bb8f3d6SRafael J. Wysocki }
660bb8f3d6SRafael J. Wysocki 
sysfs_do_create_link(struct kobject * kobj,struct kobject * target,const char * name,int warn)670bb8f3d6SRafael J. Wysocki static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
680bb8f3d6SRafael J. Wysocki 				const char *name, int warn)
690bb8f3d6SRafael J. Wysocki {
70324a56e1STejun Heo 	struct kernfs_node *parent = NULL;
710bb8f3d6SRafael J. Wysocki 
720bb8f3d6SRafael J. Wysocki 	if (!kobj)
73324a56e1STejun Heo 		parent = sysfs_root_kn;
740bb8f3d6SRafael J. Wysocki 	else
75324a56e1STejun Heo 		parent = kobj->sd;
760bb8f3d6SRafael J. Wysocki 
77324a56e1STejun Heo 	if (!parent)
780bb8f3d6SRafael J. Wysocki 		return -EFAULT;
790bb8f3d6SRafael J. Wysocki 
80324a56e1STejun Heo 	return sysfs_do_create_link_sd(parent, target, name, warn);
810bb8f3d6SRafael J. Wysocki }
820bb8f3d6SRafael J. Wysocki 
830bb8f3d6SRafael J. Wysocki /**
8436ce6dadSCornelia Huck  *	sysfs_create_link - create symlink between two objects.
8536ce6dadSCornelia Huck  *	@kobj:	object whose directory we're creating the link in.
8636ce6dadSCornelia Huck  *	@target:	object we're pointing to.
8736ce6dadSCornelia Huck  *	@name:		name of the symlink.
8836ce6dadSCornelia Huck  */
sysfs_create_link(struct kobject * kobj,struct kobject * target,const char * name)8936ce6dadSCornelia Huck int sysfs_create_link(struct kobject *kobj, struct kobject *target,
9036ce6dadSCornelia Huck 		      const char *name)
9136ce6dadSCornelia Huck {
9236ce6dadSCornelia Huck 	return sysfs_do_create_link(kobj, target, name, 1);
9336ce6dadSCornelia Huck }
941b866757SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(sysfs_create_link);
9536ce6dadSCornelia Huck 
9636ce6dadSCornelia Huck /**
9736ce6dadSCornelia Huck  *	sysfs_create_link_nowarn - create symlink between two objects.
9836ce6dadSCornelia Huck  *	@kobj:	object whose directory we're creating the link in.
9936ce6dadSCornelia Huck  *	@target:	object we're pointing to.
10036ce6dadSCornelia Huck  *	@name:		name of the symlink.
10136ce6dadSCornelia Huck  *
1026f1cbd4aSRobert P. J. Day  *	This function does the same as sysfs_create_link(), but it
10336ce6dadSCornelia Huck  *	doesn't warn if the link already exists.
10436ce6dadSCornelia Huck  */
sysfs_create_link_nowarn(struct kobject * kobj,struct kobject * target,const char * name)10536ce6dadSCornelia Huck int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
10636ce6dadSCornelia Huck 			     const char *name)
10736ce6dadSCornelia Huck {
10836ce6dadSCornelia Huck 	return sysfs_do_create_link(kobj, target, name, 0);
10936ce6dadSCornelia Huck }
1102399ac42SGrygorii Strashko EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn);
11136ce6dadSCornelia Huck 
11236ce6dadSCornelia Huck /**
113746edb7aSEric W. Biederman  *	sysfs_delete_link - remove symlink in object's directory.
114746edb7aSEric W. Biederman  *	@kobj:	object we're acting for.
115746edb7aSEric W. Biederman  *	@targ:	object we're pointing to.
116746edb7aSEric W. Biederman  *	@name:	name of the symlink to remove.
117746edb7aSEric W. Biederman  *
118746edb7aSEric W. Biederman  *	Unlike sysfs_remove_link sysfs_delete_link has enough information
119746edb7aSEric W. Biederman  *	to successfully delete symlinks in tagged directories.
120746edb7aSEric W. Biederman  */
sysfs_delete_link(struct kobject * kobj,struct kobject * targ,const char * name)121746edb7aSEric W. Biederman void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
122746edb7aSEric W. Biederman 			const char *name)
123746edb7aSEric W. Biederman {
124746edb7aSEric W. Biederman 	const void *ns = NULL;
1250cae60f9STejun Heo 
1260cae60f9STejun Heo 	/*
1270cae60f9STejun Heo 	 * We don't own @target and it may be removed at any time.
1280cae60f9STejun Heo 	 * Synchronize using sysfs_symlink_target_lock.  See
1290cae60f9STejun Heo 	 * sysfs_remove_dir() for details.
1300cae60f9STejun Heo 	 */
1310cae60f9STejun Heo 	spin_lock(&sysfs_symlink_target_lock);
132ac9bba03STejun Heo 	if (targ->sd && kernfs_ns_enabled(kobj->sd))
133adc5e8b5STejun Heo 		ns = targ->sd->ns;
1340cae60f9STejun Heo 	spin_unlock(&sysfs_symlink_target_lock);
135879f40d1STejun Heo 	kernfs_remove_by_name_ns(kobj->sd, name, ns);
136746edb7aSEric W. Biederman }
137746edb7aSEric W. Biederman 
138746edb7aSEric W. Biederman /**
1391da177e4SLinus Torvalds  *	sysfs_remove_link - remove symlink in object's directory.
1401da177e4SLinus Torvalds  *	@kobj:	object we're acting for.
1411da177e4SLinus Torvalds  *	@name:	name of the symlink to remove.
1421da177e4SLinus Torvalds  */
sysfs_remove_link(struct kobject * kobj,const char * name)143e3a15db2SDmitry Torokhov void sysfs_remove_link(struct kobject *kobj, const char *name)
1441da177e4SLinus Torvalds {
145324a56e1STejun Heo 	struct kernfs_node *parent = NULL;
146a839c5afSMark Fasheh 
147a839c5afSMark Fasheh 	if (!kobj)
148324a56e1STejun Heo 		parent = sysfs_root_kn;
149a839c5afSMark Fasheh 	else
150324a56e1STejun Heo 		parent = kobj->sd;
151a839c5afSMark Fasheh 
152324a56e1STejun Heo 	kernfs_remove_by_name(parent, name);
1531da177e4SLinus Torvalds }
1541b866757SGreg Kroah-Hartman EXPORT_SYMBOL_GPL(sysfs_remove_link);
1551da177e4SLinus Torvalds 
1567cb32942SEric W. Biederman /**
1574b30ee58STejun Heo  *	sysfs_rename_link_ns - rename symlink in object's directory.
1587cb32942SEric W. Biederman  *	@kobj:	object we're acting for.
1597cb32942SEric W. Biederman  *	@targ:	object we're pointing to.
1607cb32942SEric W. Biederman  *	@old:	previous name of the symlink.
1617cb32942SEric W. Biederman  *	@new:	new name of the symlink.
1624b30ee58STejun Heo  *	@new_ns: new namespace of the symlink.
1637cb32942SEric W. Biederman  *
1647cb32942SEric W. Biederman  *	A helper function for the common rename symlink idiom.
1657cb32942SEric W. Biederman  */
sysfs_rename_link_ns(struct kobject * kobj,struct kobject * targ,const char * old,const char * new,const void * new_ns)1664b30ee58STejun Heo int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
1674b30ee58STejun Heo 			 const char *old, const char *new, const void *new_ns)
1687cb32942SEric W. Biederman {
169324a56e1STejun Heo 	struct kernfs_node *parent, *kn = NULL;
1704b30ee58STejun Heo 	const void *old_ns = NULL;
1717cb32942SEric W. Biederman 	int result;
1727cb32942SEric W. Biederman 
1737cb32942SEric W. Biederman 	if (!kobj)
174324a56e1STejun Heo 		parent = sysfs_root_kn;
1757cb32942SEric W. Biederman 	else
176324a56e1STejun Heo 		parent = kobj->sd;
1777cb32942SEric W. Biederman 
1783ff195b0SEric W. Biederman 	if (targ->sd)
179adc5e8b5STejun Heo 		old_ns = targ->sd->ns;
1803ff195b0SEric W. Biederman 
1817cb32942SEric W. Biederman 	result = -ENOENT;
182324a56e1STejun Heo 	kn = kernfs_find_and_get_ns(parent, old, old_ns);
183324a56e1STejun Heo 	if (!kn)
1847cb32942SEric W. Biederman 		goto out;
1857cb32942SEric W. Biederman 
1867cb32942SEric W. Biederman 	result = -EINVAL;
187df23fc39STejun Heo 	if (kernfs_type(kn) != KERNFS_LINK)
1887cb32942SEric W. Biederman 		goto out;
189adc5e8b5STejun Heo 	if (kn->symlink.target_kn->priv != targ)
1907cb32942SEric W. Biederman 		goto out;
1917cb32942SEric W. Biederman 
192324a56e1STejun Heo 	result = kernfs_rename_ns(kn, parent, new, new_ns);
1937cb32942SEric W. Biederman 
1947cb32942SEric W. Biederman out:
195324a56e1STejun Heo 	kernfs_put(kn);
1967cb32942SEric W. Biederman 	return result;
1977cb32942SEric W. Biederman }
1984b30ee58STejun Heo EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);
199