Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * fs/sysfs/symlink.c - sysfs symlink implementation
0004  *
0005  * Copyright (c) 2001-3 Patrick Mochel
0006  * Copyright (c) 2007 SUSE Linux Products GmbH
0007  * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
0008  *
0009  * Please see Documentation/filesystems/sysfs.rst for more information.
0010  */
0011 
0012 #include <linux/fs.h>
0013 #include <linux/module.h>
0014 #include <linux/kobject.h>
0015 #include <linux/mutex.h>
0016 #include <linux/security.h>
0017 
0018 #include "sysfs.h"
0019 
0020 static int sysfs_do_create_link_sd(struct kernfs_node *parent,
0021                    struct kobject *target_kobj,
0022                    const char *name, int warn)
0023 {
0024     struct kernfs_node *kn, *target = NULL;
0025 
0026     if (WARN_ON(!name || !parent))
0027         return -EINVAL;
0028 
0029     /*
0030      * We don't own @target_kobj and it may be removed at any time.
0031      * Synchronize using sysfs_symlink_target_lock.  See
0032      * sysfs_remove_dir() for details.
0033      */
0034     spin_lock(&sysfs_symlink_target_lock);
0035     if (target_kobj->sd) {
0036         target = target_kobj->sd;
0037         kernfs_get(target);
0038     }
0039     spin_unlock(&sysfs_symlink_target_lock);
0040 
0041     if (!target)
0042         return -ENOENT;
0043 
0044     kn = kernfs_create_link(parent, name, target);
0045     kernfs_put(target);
0046 
0047     if (!IS_ERR(kn))
0048         return 0;
0049 
0050     if (warn && PTR_ERR(kn) == -EEXIST)
0051         sysfs_warn_dup(parent, name);
0052     return PTR_ERR(kn);
0053 }
0054 
0055 /**
0056  *  sysfs_create_link_sd - create symlink to a given object.
0057  *  @kn:        directory we're creating the link in.
0058  *  @target:    object we're pointing to.
0059  *  @name:      name of the symlink.
0060  */
0061 int sysfs_create_link_sd(struct kernfs_node *kn, struct kobject *target,
0062              const char *name)
0063 {
0064     return sysfs_do_create_link_sd(kn, target, name, 1);
0065 }
0066 
0067 static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
0068                 const char *name, int warn)
0069 {
0070     struct kernfs_node *parent = NULL;
0071 
0072     if (!kobj)
0073         parent = sysfs_root_kn;
0074     else
0075         parent = kobj->sd;
0076 
0077     if (!parent)
0078         return -EFAULT;
0079 
0080     return sysfs_do_create_link_sd(parent, target, name, warn);
0081 }
0082 
0083 /**
0084  *  sysfs_create_link - create symlink between two objects.
0085  *  @kobj:  object whose directory we're creating the link in.
0086  *  @target:    object we're pointing to.
0087  *  @name:      name of the symlink.
0088  */
0089 int sysfs_create_link(struct kobject *kobj, struct kobject *target,
0090               const char *name)
0091 {
0092     return sysfs_do_create_link(kobj, target, name, 1);
0093 }
0094 EXPORT_SYMBOL_GPL(sysfs_create_link);
0095 
0096 /**
0097  *  sysfs_create_link_nowarn - create symlink between two objects.
0098  *  @kobj:  object whose directory we're creating the link in.
0099  *  @target:    object we're pointing to.
0100  *  @name:      name of the symlink.
0101  *
0102  *  This function does the same as sysfs_create_link(), but it
0103  *  doesn't warn if the link already exists.
0104  */
0105 int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
0106                  const char *name)
0107 {
0108     return sysfs_do_create_link(kobj, target, name, 0);
0109 }
0110 EXPORT_SYMBOL_GPL(sysfs_create_link_nowarn);
0111 
0112 /**
0113  *  sysfs_delete_link - remove symlink in object's directory.
0114  *  @kobj:  object we're acting for.
0115  *  @targ:  object we're pointing to.
0116  *  @name:  name of the symlink to remove.
0117  *
0118  *  Unlike sysfs_remove_link sysfs_delete_link has enough information
0119  *  to successfully delete symlinks in tagged directories.
0120  */
0121 void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
0122             const char *name)
0123 {
0124     const void *ns = NULL;
0125 
0126     /*
0127      * We don't own @target and it may be removed at any time.
0128      * Synchronize using sysfs_symlink_target_lock.  See
0129      * sysfs_remove_dir() for details.
0130      */
0131     spin_lock(&sysfs_symlink_target_lock);
0132     if (targ->sd && kernfs_ns_enabled(kobj->sd))
0133         ns = targ->sd->ns;
0134     spin_unlock(&sysfs_symlink_target_lock);
0135     kernfs_remove_by_name_ns(kobj->sd, name, ns);
0136 }
0137 
0138 /**
0139  *  sysfs_remove_link - remove symlink in object's directory.
0140  *  @kobj:  object we're acting for.
0141  *  @name:  name of the symlink to remove.
0142  */
0143 void sysfs_remove_link(struct kobject *kobj, const char *name)
0144 {
0145     struct kernfs_node *parent = NULL;
0146 
0147     if (!kobj)
0148         parent = sysfs_root_kn;
0149     else
0150         parent = kobj->sd;
0151 
0152     kernfs_remove_by_name(parent, name);
0153 }
0154 EXPORT_SYMBOL_GPL(sysfs_remove_link);
0155 
0156 /**
0157  *  sysfs_rename_link_ns - rename symlink in object's directory.
0158  *  @kobj:  object we're acting for.
0159  *  @targ:  object we're pointing to.
0160  *  @old:   previous name of the symlink.
0161  *  @new:   new name of the symlink.
0162  *  @new_ns: new namespace of the symlink.
0163  *
0164  *  A helper function for the common rename symlink idiom.
0165  */
0166 int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
0167              const char *old, const char *new, const void *new_ns)
0168 {
0169     struct kernfs_node *parent, *kn = NULL;
0170     const void *old_ns = NULL;
0171     int result;
0172 
0173     if (!kobj)
0174         parent = sysfs_root_kn;
0175     else
0176         parent = kobj->sd;
0177 
0178     if (targ->sd)
0179         old_ns = targ->sd->ns;
0180 
0181     result = -ENOENT;
0182     kn = kernfs_find_and_get_ns(parent, old, old_ns);
0183     if (!kn)
0184         goto out;
0185 
0186     result = -EINVAL;
0187     if (kernfs_type(kn) != KERNFS_LINK)
0188         goto out;
0189     if (kn->symlink.target_kn->priv != targ)
0190         goto out;
0191 
0192     result = kernfs_rename_ns(kn, parent, new, new_ns);
0193 
0194 out:
0195     kernfs_put(kn);
0196     return result;
0197 }
0198 EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);