1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * fs/sysfs/symlink.c - sysfs symlink implementation 4 * 5 * Copyright (c) 2001-3 Patrick Mochel 6 * Copyright (c) 2007 SUSE Linux Products GmbH 7 * Copyright (c) 2007 Tejun Heo <teheo@suse.de> 8 * 9 * Please see Documentation/filesystems/sysfs.txt for more information. 10 */ 11 12 #include <linux/fs.h> 13 #include <linux/module.h> 14 #include <linux/kobject.h> 15 #include <linux/mutex.h> 16 #include <linux/security.h> 17 18 #include "sysfs.h" 19 20 static int sysfs_do_create_link_sd(struct kernfs_node *parent, 21 struct kobject *target_kobj, 22 const char *name, int warn) 23 { 24 struct kernfs_node *kn, *target = NULL; 25 26 BUG_ON(!name || !parent); 27 28 /* 29 * We don't own @target_kobj and it may be removed at any time. 30 * Synchronize using sysfs_symlink_target_lock. See 31 * sysfs_remove_dir() for details. 32 */ 33 spin_lock(&sysfs_symlink_target_lock); 34 if (target_kobj->sd) { 35 target = target_kobj->sd; 36 kernfs_get(target); 37 } 38 spin_unlock(&sysfs_symlink_target_lock); 39 40 if (!target) 41 return -ENOENT; 42 43 kn = kernfs_create_link(parent, name, target); 44 kernfs_put(target); 45 46 if (!IS_ERR(kn)) 47 return 0; 48 49 if (warn && PTR_ERR(kn) == -EEXIST) 50 sysfs_warn_dup(parent, name); 51 return PTR_ERR(kn); 52 } 53 54 /** 55 * sysfs_create_link_sd - create symlink to a given object. 56 * @kn: directory we're creating the link in. 57 * @target: object we're pointing to. 58 * @name: name of the symlink. 59 */ 60 int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target, 61 const char *name) 62 { 63 return sysfs_do_create_link_sd(kn, target, name, 1); 64 } 65 66 static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target, 67 const char *name, int warn) 68 { 69 struct kernfs_node *parent = NULL; 70 71 if (!kobj) 72 parent = sysfs_root_kn; 73 else 74 parent = kobj->sd; 75 76 if (!parent) 77 return -EFAULT; 78 79 return sysfs_do_create_link_sd(parent, target, name, warn); 80 } 81 82 /** 83 * sysfs_create_link - create symlink between two objects. 84 * @kobj: object whose directory we're creating the link in. 85 * @target: object we're pointing to. 86 * @name: name of the symlink. 87 */ 88 int sysfs_create_link(struct kobject *kobj, struct kobject *target, 89 const char *name) 90 { 91 return sysfs_do_create_link(kobj, target, name, 1); 92 } 93 EXPORT_SYMBOL_GPL(sysfs_create_link); 94 95 /** 96 * sysfs_create_link_nowarn - create symlink between two objects. 97 * @kobj: object whose directory we're creating the link in. 98 * @target: object we're pointing to. 99 * @name: name of the symlink. 100 * 101 * This function does the same as sysfs_create_link(), but it 102 * doesn't warn if the link already exists. 103 */ 104 int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target, 105 const char *name) 106 { 107 return sysfs_do_create_link(kobj, target, name, 0); 108 } 109 EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn); 110 111 /** 112 * sysfs_delete_link - remove symlink in object's directory. 113 * @kobj: object we're acting for. 114 * @targ: object we're pointing to. 115 * @name: name of the symlink to remove. 116 * 117 * Unlike sysfs_remove_link sysfs_delete_link has enough information 118 * to successfully delete symlinks in tagged directories. 119 */ 120 void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, 121 const char *name) 122 { 123 const void *ns = NULL; 124 125 /* 126 * We don't own @target and it may be removed at any time. 127 * Synchronize using sysfs_symlink_target_lock. See 128 * sysfs_remove_dir() for details. 129 */ 130 spin_lock(&sysfs_symlink_target_lock); 131 if (targ->sd && kernfs_ns_enabled(kobj->sd)) 132 ns = targ->sd->ns; 133 spin_unlock(&sysfs_symlink_target_lock); 134 kernfs_remove_by_name_ns(kobj->sd, name, ns); 135 } 136 137 /** 138 * sysfs_remove_link - remove symlink in object's directory. 139 * @kobj: object we're acting for. 140 * @name: name of the symlink to remove. 141 */ 142 void sysfs_remove_link(struct kobject *kobj, const char *name) 143 { 144 struct kernfs_node *parent = NULL; 145 146 if (!kobj) 147 parent = sysfs_root_kn; 148 else 149 parent = kobj->sd; 150 151 kernfs_remove_by_name(parent, name); 152 } 153 EXPORT_SYMBOL_GPL(sysfs_remove_link); 154 155 /** 156 * sysfs_rename_link_ns - rename symlink in object's directory. 157 * @kobj: object we're acting for. 158 * @targ: object we're pointing to. 159 * @old: previous name of the symlink. 160 * @new: new name of the symlink. 161 * @new_ns: new namespace of the symlink. 162 * 163 * A helper function for the common rename symlink idiom. 164 */ 165 int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ, 166 const char *old, const char *new, const void *new_ns) 167 { 168 struct kernfs_node *parent, *kn = NULL; 169 const void *old_ns = NULL; 170 int result; 171 172 if (!kobj) 173 parent = sysfs_root_kn; 174 else 175 parent = kobj->sd; 176 177 if (targ->sd) 178 old_ns = targ->sd->ns; 179 180 result = -ENOENT; 181 kn = kernfs_find_and_get_ns(parent, old, old_ns); 182 if (!kn) 183 goto out; 184 185 result = -EINVAL; 186 if (kernfs_type(kn) != KERNFS_LINK) 187 goto out; 188 if (kn->symlink.target_kn->priv != targ) 189 goto out; 190 191 result = kernfs_rename_ns(kn, parent, new, new_ns); 192 193 out: 194 kernfs_put(kn); 195 return result; 196 } 197 EXPORT_SYMBOL_GPL(sysfs_rename_link_ns); 198