LCOV - code coverage report
Current view: top level - fs/sysfs - symlink.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 52 90 57.8 %
Date: 2014-02-18 Functions: 6 11 54.5 %
Branches: 29 72 40.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * fs/sysfs/symlink.c - sysfs symlink implementation
       3                 :            :  *
       4                 :            :  * Copyright (c) 2001-3 Patrick Mochel
       5                 :            :  * Copyright (c) 2007 SUSE Linux Products GmbH
       6                 :            :  * Copyright (c) 2007 Tejun Heo <teheo@suse.de>
       7                 :            :  *
       8                 :            :  * This file is released under the GPLv2.
       9                 :            :  *
      10                 :            :  * Please see Documentation/filesystems/sysfs.txt for more information.
      11                 :            :  */
      12                 :            : 
      13                 :            : #include <linux/fs.h>
      14                 :            : #include <linux/gfp.h>
      15                 :            : #include <linux/mount.h>
      16                 :            : #include <linux/module.h>
      17                 :            : #include <linux/kobject.h>
      18                 :            : #include <linux/namei.h>
      19                 :            : #include <linux/mutex.h>
      20                 :            : #include <linux/security.h>
      21                 :            : 
      22                 :            : #include "sysfs.h"
      23                 :            : 
      24                 :          0 : static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
      25                 :            :                                    struct kobject *target,
      26                 :            :                                    const char *name, int warn)
      27                 :            : {
      28                 :            :         struct sysfs_dirent *target_sd = NULL;
      29                 :            :         struct sysfs_dirent *sd = NULL;
      30                 :            :         struct sysfs_addrm_cxt acxt;
      31                 :            :         enum kobj_ns_type ns_type;
      32                 :            :         int error;
      33                 :            : 
      34         [ -  + ]:        336 :         BUG_ON(!name || !parent_sd);
      35                 :            : 
      36                 :            :         /*
      37                 :            :          * We don't own @target and it may be removed at any time.
      38                 :            :          * Synchronize using sysfs_symlink_target_lock.  See
      39                 :            :          * sysfs_remove_dir() for details.
      40                 :            :          */
      41                 :            :         spin_lock(&sysfs_symlink_target_lock);
      42         [ +  - ]:        336 :         if (target->sd)
      43                 :            :                 target_sd = sysfs_get(target->sd);
      44                 :            :         spin_unlock(&sysfs_symlink_target_lock);
      45                 :            : 
      46                 :            :         error = -ENOENT;
      47         [ +  - ]:        336 :         if (!target_sd)
      48                 :            :                 goto out_put;
      49                 :            : 
      50                 :            :         error = -ENOMEM;
      51                 :        336 :         sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK);
      52         [ +  - ]:        336 :         if (!sd)
      53                 :            :                 goto out_put;
      54                 :            : 
      55                 :            :         ns_type = sysfs_ns_type(parent_sd);
      56         [ -  + ]:        336 :         if (ns_type)
      57                 :          0 :                 sd->s_ns = target_sd->s_ns;
      58                 :        336 :         sd->s_symlink.target_sd = target_sd;
      59                 :            :         target_sd = NULL;       /* reference is now owned by the symlink */
      60                 :            : 
      61                 :        336 :         sysfs_addrm_start(&acxt);
      62                 :            :         /* Symlinks must be between directories with the same ns_type */
      63 [ -  + ][ #  # ]:        336 :         if (!ns_type ||
      64                 :          0 :             (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) {
      65         [ +  - ]:        336 :                 if (warn)
      66                 :        336 :                         error = sysfs_add_one(&acxt, sd, parent_sd);
      67                 :            :                 else
      68                 :          0 :                         error = __sysfs_add_one(&acxt, sd, parent_sd);
      69                 :            :         } else {
      70                 :            :                 error = -EINVAL;
      71                 :          0 :                 WARN(1, KERN_WARNING
      72                 :            :                         "sysfs: symlink across ns_types %s/%s -> %s/%s\n",
      73                 :            :                         parent_sd->s_name,
      74                 :            :                         sd->s_name,
      75                 :            :                         sd->s_symlink.target_sd->s_parent->s_name,
      76                 :            :                         sd->s_symlink.target_sd->s_name);
      77                 :            :         }
      78                 :        336 :         sysfs_addrm_finish(&acxt);
      79                 :            : 
      80         [ +  - ]:        336 :         if (error)
      81                 :            :                 goto out_put;
      82                 :            : 
      83                 :            :         return 0;
      84                 :            : 
      85                 :            :  out_put:
      86                 :            :         sysfs_put(target_sd);
      87                 :            :         sysfs_put(sd);
      88                 :            :         return error;
      89                 :            : }
      90                 :            : 
      91                 :            : /**
      92                 :            :  *      sysfs_create_link_sd - create symlink to a given object.
      93                 :            :  *      @sd:            directory we're creating the link in.
      94                 :            :  *      @target:        object we're pointing to.
      95                 :            :  *      @name:          name of the symlink.
      96                 :            :  */
      97                 :          0 : int sysfs_create_link_sd(struct sysfs_dirent *sd, struct kobject *target,
      98                 :            :                          const char *name)
      99                 :            : {
     100                 :          0 :         return sysfs_do_create_link_sd(sd, target, name, 1);
     101                 :            : }
     102                 :            : 
     103                 :            : static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
     104                 :            :                                 const char *name, int warn)
     105                 :            : {
     106                 :            :         struct sysfs_dirent *parent_sd = NULL;
     107                 :            : 
     108 [ #  # ][ +  - ]:        336 :         if (!kobj)
     109                 :            :                 parent_sd = &sysfs_root;
     110                 :            :         else
     111                 :        336 :                 parent_sd = kobj->sd;
     112                 :            : 
     113 [ #  # ][ +  - ]:        336 :         if (!parent_sd)
     114                 :            :                 return -EFAULT;
     115                 :            : 
     116                 :        336 :         return sysfs_do_create_link_sd(parent_sd, target, name, warn);
     117                 :            : }
     118                 :            : 
     119                 :            : /**
     120                 :            :  *      sysfs_create_link - create symlink between two objects.
     121                 :            :  *      @kobj:  object whose directory we're creating the link in.
     122                 :            :  *      @target:        object we're pointing to.
     123                 :            :  *      @name:          name of the symlink.
     124                 :            :  */
     125                 :          0 : int sysfs_create_link(struct kobject *kobj, struct kobject *target,
     126                 :            :                       const char *name)
     127                 :            : {
     128                 :          0 :         return sysfs_do_create_link(kobj, target, name, 1);
     129                 :            : }
     130                 :            : EXPORT_SYMBOL_GPL(sysfs_create_link);
     131                 :            : 
     132                 :            : /**
     133                 :            :  *      sysfs_create_link_nowarn - create symlink between two objects.
     134                 :            :  *      @kobj:  object whose directory we're creating the link in.
     135                 :            :  *      @target:        object we're pointing to.
     136                 :            :  *      @name:          name of the symlink.
     137                 :            :  *
     138                 :            :  *      This function does the same as sysfs_create_link(), but it
     139                 :            :  *      doesn't warn if the link already exists.
     140                 :            :  */
     141                 :          0 : int sysfs_create_link_nowarn(struct kobject *kobj, struct kobject *target,
     142                 :            :                              const char *name)
     143                 :            : {
     144                 :          0 :         return sysfs_do_create_link(kobj, target, name, 0);
     145                 :            : }
     146                 :            : 
     147                 :            : /**
     148                 :            :  *      sysfs_delete_link - remove symlink in object's directory.
     149                 :            :  *      @kobj:  object we're acting for.
     150                 :            :  *      @targ:  object we're pointing to.
     151                 :            :  *      @name:  name of the symlink to remove.
     152                 :            :  *
     153                 :            :  *      Unlike sysfs_remove_link sysfs_delete_link has enough information
     154                 :            :  *      to successfully delete symlinks in tagged directories.
     155                 :            :  */
     156                 :          0 : void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
     157                 :            :                         const char *name)
     158                 :            : {
     159                 :            :         const void *ns = NULL;
     160                 :            : 
     161                 :            :         /*
     162                 :            :          * We don't own @target and it may be removed at any time.
     163                 :            :          * Synchronize using sysfs_symlink_target_lock.  See
     164                 :            :          * sysfs_remove_dir() for details.
     165                 :            :          */
     166                 :            :         spin_lock(&sysfs_symlink_target_lock);
     167 [ #  # ][ #  # ]:          0 :         if (targ->sd && sysfs_ns_type(kobj->sd))
     168                 :          0 :                 ns = targ->sd->s_ns;
     169                 :            :         spin_unlock(&sysfs_symlink_target_lock);
     170                 :          0 :         sysfs_hash_and_remove(kobj->sd, name, ns);
     171                 :          0 : }
     172                 :            : 
     173                 :            : /**
     174                 :            :  *      sysfs_remove_link - remove symlink in object's directory.
     175                 :            :  *      @kobj:  object we're acting for.
     176                 :            :  *      @name:  name of the symlink to remove.
     177                 :            :  */
     178                 :          0 : void sysfs_remove_link(struct kobject *kobj, const char *name)
     179                 :            : {
     180                 :            :         struct sysfs_dirent *parent_sd = NULL;
     181                 :            : 
     182         [ #  # ]:          0 :         if (!kobj)
     183                 :            :                 parent_sd = &sysfs_root;
     184                 :            :         else
     185                 :          0 :                 parent_sd = kobj->sd;
     186                 :            : 
     187                 :          0 :         sysfs_hash_and_remove(parent_sd, name, NULL);
     188                 :          0 : }
     189                 :            : EXPORT_SYMBOL_GPL(sysfs_remove_link);
     190                 :            : 
     191                 :            : /**
     192                 :            :  *      sysfs_rename_link_ns - rename symlink in object's directory.
     193                 :            :  *      @kobj:  object we're acting for.
     194                 :            :  *      @targ:  object we're pointing to.
     195                 :            :  *      @old:   previous name of the symlink.
     196                 :            :  *      @new:   new name of the symlink.
     197                 :            :  *      @new_ns: new namespace of the symlink.
     198                 :            :  *
     199                 :            :  *      A helper function for the common rename symlink idiom.
     200                 :            :  */
     201                 :          0 : int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *targ,
     202                 :            :                          const char *old, const char *new, const void *new_ns)
     203                 :            : {
     204                 :          0 :         struct sysfs_dirent *parent_sd, *sd = NULL;
     205                 :            :         const void *old_ns = NULL;
     206                 :            :         int result;
     207                 :            : 
     208         [ #  # ]:          0 :         if (!kobj)
     209                 :            :                 parent_sd = &sysfs_root;
     210                 :            :         else
     211                 :          0 :                 parent_sd = kobj->sd;
     212                 :            : 
     213         [ #  # ]:          0 :         if (targ->sd)
     214                 :          0 :                 old_ns = targ->sd->s_ns;
     215                 :            : 
     216                 :            :         result = -ENOENT;
     217                 :          0 :         sd = sysfs_get_dirent_ns(parent_sd, old, old_ns);
     218         [ #  # ]:          0 :         if (!sd)
     219                 :            :                 goto out;
     220                 :            : 
     221                 :            :         result = -EINVAL;
     222         [ #  # ]:          0 :         if (sysfs_type(sd) != SYSFS_KOBJ_LINK)
     223                 :            :                 goto out;
     224         [ #  # ]:          0 :         if (sd->s_symlink.target_sd->s_dir.kobj != targ)
     225                 :            :                 goto out;
     226                 :            : 
     227                 :          0 :         result = sysfs_rename(sd, parent_sd, new, new_ns);
     228                 :            : 
     229                 :            : out:
     230                 :            :         sysfs_put(sd);
     231                 :          0 :         return result;
     232                 :            : }
     233                 :            : EXPORT_SYMBOL_GPL(sysfs_rename_link_ns);
     234                 :            : 
     235                 :          0 : static int sysfs_get_target_path(struct sysfs_dirent *parent_sd,
     236                 :            :                                  struct sysfs_dirent *target_sd, char *path)
     237                 :            : {
     238                 :            :         struct sysfs_dirent *base, *sd;
     239                 :            :         char *s = path;
     240                 :            :         int len = 0;
     241                 :            : 
     242                 :            :         /* go up to the root, stop at the base */
     243                 :            :         base = parent_sd;
     244         [ +  + ]:        598 :         while (base->s_parent) {
     245                 :        472 :                 sd = target_sd->s_parent;
     246 [ +  + ][ +  - ]:       1228 :                 while (sd->s_parent && base != sd)
     247                 :            :                         sd = sd->s_parent;
     248                 :            : 
     249         [ +  - ]:        472 :                 if (base == sd)
     250                 :            :                         break;
     251                 :            : 
     252                 :        472 :                 strcpy(s, "../");
     253                 :        472 :                 s += 3;
     254                 :        472 :                 base = base->s_parent;
     255                 :            :         }
     256                 :            : 
     257                 :            :         /* determine end of target string for reverse fillup */
     258                 :            :         sd = target_sd;
     259 [ +  + ][ +  - ]:        542 :         while (sd->s_parent && sd != base) {
     260                 :        416 :                 len += strlen(sd->s_name) + 1;
     261                 :            :                 sd = sd->s_parent;
     262                 :            :         }
     263                 :            : 
     264                 :            :         /* check limits */
     265         [ +  - ]:        126 :         if (len < 2)
     266                 :            :                 return -EINVAL;
     267                 :        126 :         len--;
     268         [ +  - ]:        126 :         if ((s - path) + len > PATH_MAX)
     269                 :            :                 return -ENAMETOOLONG;
     270                 :            : 
     271                 :            :         /* reverse fillup of target string from target to base */
     272                 :            :         sd = target_sd;
     273 [ +  - ][ +  - ]:        542 :         while (sd->s_parent && sd != base) {
     274                 :        416 :                 int slen = strlen(sd->s_name);
     275                 :            : 
     276                 :        416 :                 len -= slen;
     277                 :        416 :                 strncpy(s + len, sd->s_name, slen);
     278         [ +  + ]:        416 :                 if (len)
     279                 :        290 :                         s[--len] = '/';
     280                 :            : 
     281                 :        416 :                 sd = sd->s_parent;
     282                 :            :         }
     283                 :            : 
     284                 :            :         return 0;
     285                 :            : }
     286                 :            : 
     287                 :        126 : static int sysfs_getlink(struct dentry *dentry, char *path)
     288                 :            : {
     289                 :        126 :         struct sysfs_dirent *sd = dentry->d_fsdata;
     290                 :        126 :         struct sysfs_dirent *parent_sd = sd->s_parent;
     291                 :        126 :         struct sysfs_dirent *target_sd = sd->s_symlink.target_sd;
     292                 :            :         int error;
     293                 :            : 
     294                 :        126 :         mutex_lock(&sysfs_mutex);
     295                 :        126 :         error = sysfs_get_target_path(parent_sd, target_sd, path);
     296                 :        126 :         mutex_unlock(&sysfs_mutex);
     297                 :            : 
     298                 :        126 :         return error;
     299                 :            : }
     300                 :            : 
     301                 :          0 : static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd)
     302                 :            : {
     303                 :            :         int error = -ENOMEM;
     304                 :        126 :         unsigned long page = get_zeroed_page(GFP_KERNEL);
     305         [ +  - ]:        126 :         if (page) {
     306                 :        126 :                 error = sysfs_getlink(dentry, (char *) page);
     307         [ -  + ]:        126 :                 if (error < 0)
     308                 :          0 :                         free_page((unsigned long)page);
     309                 :            :         }
     310         [ -  + ]:        252 :         nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
     311                 :        126 :         return NULL;
     312                 :            : }
     313                 :            : 
     314                 :          0 : static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd,
     315                 :            :                            void *cookie)
     316                 :            : {
     317                 :            :         char *page = nd_get_link(nd);
     318         [ +  - ]:        126 :         if (!IS_ERR(page))
     319                 :        126 :                 free_page((unsigned long)page);
     320                 :          0 : }
     321                 :            : 
     322                 :            : const struct inode_operations sysfs_symlink_inode_operations = {
     323                 :            :         .setxattr       = sysfs_setxattr,
     324                 :            :         .readlink       = generic_readlink,
     325                 :            :         .follow_link    = sysfs_follow_link,
     326                 :            :         .put_link       = sysfs_put_link,
     327                 :            :         .setattr        = sysfs_setattr,
     328                 :            :         .getattr        = sysfs_getattr,
     329                 :            :         .permission     = sysfs_permission,
     330                 :            : };

Generated by: LCOV version 1.9