LCOV - code coverage report
Current view: top level - fs/sysfs - symlink.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 32 59 54.2 %
Date: 2023-04-06 08:38:28 Functions: 4 7 57.1 %

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

Generated by: LCOV version 1.14