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/mount.h> 15 #include <linux/module.h> 16 #include <linux/kobject.h> 17 #include <linux/namei.h> 18 #include <linux/mutex.h> 19 20 #include "sysfs.h" 21 22 static int object_depth(struct sysfs_dirent *sd) 23 { 24 int depth = 0; 25 26 for (; sd->s_parent; sd = sd->s_parent) 27 depth++; 28 29 return depth; 30 } 31 32 static int object_path_length(struct sysfs_dirent * sd) 33 { 34 int length = 1; 35 36 for (; sd->s_parent; sd = sd->s_parent) 37 length += strlen(sd->s_name) + 1; 38 39 return length; 40 } 41 42 static void fill_object_path(struct sysfs_dirent *sd, char *buffer, int length) 43 { 44 --length; 45 for (; sd->s_parent; sd = sd->s_parent) { 46 int cur = strlen(sd->s_name); 47 48 /* back up enough to print this bus id with '/' */ 49 length -= cur; 50 strncpy(buffer + length, sd->s_name, cur); 51 *(buffer + --length) = '/'; 52 } 53 } 54 55 /** 56 * sysfs_create_link - create symlink between two objects. 57 * @kobj: object whose directory we're creating the link in. 58 * @target: object we're pointing to. 59 * @name: name of the symlink. 60 */ 61 int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) 62 { 63 struct sysfs_dirent *parent_sd = NULL; 64 struct sysfs_dirent *target_sd = NULL; 65 struct sysfs_dirent *sd = NULL; 66 struct sysfs_addrm_cxt acxt; 67 int error; 68 69 BUG_ON(!name); 70 71 if (!kobj) 72 parent_sd = &sysfs_root; 73 else 74 parent_sd = kobj->sd; 75 76 error = -EFAULT; 77 if (!parent_sd) 78 goto out_put; 79 80 /* target->sd can go away beneath us but is protected with 81 * sysfs_assoc_lock. Fetch target_sd from it. 82 */ 83 spin_lock(&sysfs_assoc_lock); 84 if (target->sd) 85 target_sd = sysfs_get(target->sd); 86 spin_unlock(&sysfs_assoc_lock); 87 88 error = -ENOENT; 89 if (!target_sd) 90 goto out_put; 91 92 error = -ENOMEM; 93 sd = sysfs_new_dirent(name, S_IFLNK|S_IRWXUGO, SYSFS_KOBJ_LINK); 94 if (!sd) 95 goto out_put; 96 97 sd->s_symlink.target_sd = target_sd; 98 target_sd = NULL; /* reference is now owned by the symlink */ 99 100 sysfs_addrm_start(&acxt, parent_sd); 101 error = sysfs_add_one(&acxt, sd); 102 sysfs_addrm_finish(&acxt); 103 104 if (error) 105 goto out_put; 106 107 return 0; 108 109 out_put: 110 sysfs_put(target_sd); 111 sysfs_put(sd); 112 return error; 113 } 114 115 116 /** 117 * sysfs_remove_link - remove symlink in object's directory. 118 * @kobj: object we're acting for. 119 * @name: name of the symlink to remove. 120 */ 121 122 void sysfs_remove_link(struct kobject * kobj, const char * name) 123 { 124 sysfs_hash_and_remove(kobj->sd, name); 125 } 126 127 static int sysfs_get_target_path(struct sysfs_dirent * parent_sd, 128 struct sysfs_dirent * target_sd, char *path) 129 { 130 char * s; 131 int depth, size; 132 133 depth = object_depth(parent_sd); 134 size = object_path_length(target_sd) + depth * 3 - 1; 135 if (size > PATH_MAX) 136 return -ENAMETOOLONG; 137 138 pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); 139 140 for (s = path; depth--; s += 3) 141 strcpy(s,"../"); 142 143 fill_object_path(target_sd, path, size); 144 pr_debug("%s: path = '%s'\n", __FUNCTION__, path); 145 146 return 0; 147 } 148 149 static int sysfs_getlink(struct dentry *dentry, char * path) 150 { 151 struct sysfs_dirent *sd = dentry->d_fsdata; 152 struct sysfs_dirent *parent_sd = sd->s_parent; 153 struct sysfs_dirent *target_sd = sd->s_symlink.target_sd; 154 int error; 155 156 mutex_lock(&sysfs_mutex); 157 error = sysfs_get_target_path(parent_sd, target_sd, path); 158 mutex_unlock(&sysfs_mutex); 159 160 return error; 161 } 162 163 static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) 164 { 165 int error = -ENOMEM; 166 unsigned long page = get_zeroed_page(GFP_KERNEL); 167 if (page) 168 error = sysfs_getlink(dentry, (char *) page); 169 nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); 170 return NULL; 171 } 172 173 static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) 174 { 175 char *page = nd_get_link(nd); 176 if (!IS_ERR(page)) 177 free_page((unsigned long)page); 178 } 179 180 const struct inode_operations sysfs_symlink_inode_operations = { 181 .readlink = generic_readlink, 182 .follow_link = sysfs_follow_link, 183 .put_link = sysfs_put_link, 184 }; 185 186 187 EXPORT_SYMBOL_GPL(sysfs_create_link); 188 EXPORT_SYMBOL_GPL(sysfs_remove_link); 189