1 /* 2 * symlink.c - operations for sysfs symlinks. 3 */ 4 5 #include <linux/fs.h> 6 #include <linux/mount.h> 7 #include <linux/module.h> 8 #include <linux/kobject.h> 9 #include <linux/namei.h> 10 #include <asm/semaphore.h> 11 12 #include "sysfs.h" 13 14 static int object_depth(struct kobject * kobj) 15 { 16 struct kobject * p = kobj; 17 int depth = 0; 18 do { depth++; } while ((p = p->parent)); 19 return depth; 20 } 21 22 static int object_path_length(struct kobject * kobj) 23 { 24 struct kobject * p = kobj; 25 int length = 1; 26 do { 27 length += strlen(kobject_name(p)) + 1; 28 p = p->parent; 29 } while (p); 30 return length; 31 } 32 33 static void fill_object_path(struct kobject * kobj, char * buffer, int length) 34 { 35 struct kobject * p; 36 37 --length; 38 for (p = kobj; p; p = p->parent) { 39 int cur = strlen(kobject_name(p)); 40 41 /* back up enough to print this bus id with '/' */ 42 length -= cur; 43 strncpy(buffer + length,kobject_name(p),cur); 44 *(buffer + --length) = '/'; 45 } 46 } 47 48 static int sysfs_add_link(struct dentry * parent, const char * name, struct kobject * target) 49 { 50 struct sysfs_dirent * parent_sd = parent->d_fsdata; 51 struct sysfs_symlink * sl; 52 int error = 0; 53 54 error = -ENOMEM; 55 sl = kmalloc(sizeof(*sl), GFP_KERNEL); 56 if (!sl) 57 goto exit1; 58 59 sl->link_name = kmalloc(strlen(name) + 1, GFP_KERNEL); 60 if (!sl->link_name) 61 goto exit2; 62 63 strcpy(sl->link_name, name); 64 sl->target_kobj = kobject_get(target); 65 66 error = sysfs_make_dirent(parent_sd, NULL, sl, S_IFLNK|S_IRWXUGO, 67 SYSFS_KOBJ_LINK); 68 if (!error) 69 return 0; 70 71 kobject_put(target); 72 kfree(sl->link_name); 73 exit2: 74 kfree(sl); 75 exit1: 76 return error; 77 } 78 79 /** 80 * sysfs_create_link - create symlink between two objects. 81 * @kobj: object whose directory we're creating the link in. 82 * @target: object we're pointing to. 83 * @name: name of the symlink. 84 */ 85 int sysfs_create_link(struct kobject * kobj, struct kobject * target, const char * name) 86 { 87 struct dentry *dentry = NULL; 88 int error = -EEXIST; 89 90 BUG_ON(!name); 91 92 if (!kobj) { 93 if (sysfs_mount && sysfs_mount->mnt_sb) 94 dentry = sysfs_mount->mnt_sb->s_root; 95 } else 96 dentry = kobj->dentry; 97 98 if (!dentry) 99 return -EFAULT; 100 101 mutex_lock(&dentry->d_inode->i_mutex); 102 if (!sysfs_dirent_exist(dentry->d_fsdata, name)) 103 error = sysfs_add_link(dentry, name, target); 104 mutex_unlock(&dentry->d_inode->i_mutex); 105 return error; 106 } 107 108 109 /** 110 * sysfs_remove_link - remove symlink in object's directory. 111 * @kobj: object we're acting for. 112 * @name: name of the symlink to remove. 113 */ 114 115 void sysfs_remove_link(struct kobject * kobj, const char * name) 116 { 117 sysfs_hash_and_remove(kobj->dentry,name); 118 } 119 120 static int sysfs_get_target_path(struct kobject * kobj, struct kobject * target, 121 char *path) 122 { 123 char * s; 124 int depth, size; 125 126 depth = object_depth(kobj); 127 size = object_path_length(target) + depth * 3 - 1; 128 if (size > PATH_MAX) 129 return -ENAMETOOLONG; 130 131 pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size); 132 133 for (s = path; depth--; s += 3) 134 strcpy(s,"../"); 135 136 fill_object_path(target, path, size); 137 pr_debug("%s: path = '%s'\n", __FUNCTION__, path); 138 139 return 0; 140 } 141 142 static int sysfs_getlink(struct dentry *dentry, char * path) 143 { 144 struct kobject *kobj, *target_kobj; 145 int error = 0; 146 147 kobj = sysfs_get_kobject(dentry->d_parent); 148 if (!kobj) 149 return -EINVAL; 150 151 target_kobj = sysfs_get_kobject(dentry); 152 if (!target_kobj) { 153 kobject_put(kobj); 154 return -EINVAL; 155 } 156 157 down_read(&sysfs_rename_sem); 158 error = sysfs_get_target_path(kobj, target_kobj, path); 159 up_read(&sysfs_rename_sem); 160 161 kobject_put(kobj); 162 kobject_put(target_kobj); 163 return error; 164 165 } 166 167 static void *sysfs_follow_link(struct dentry *dentry, struct nameidata *nd) 168 { 169 int error = -ENOMEM; 170 unsigned long page = get_zeroed_page(GFP_KERNEL); 171 if (page) 172 error = sysfs_getlink(dentry, (char *) page); 173 nd_set_link(nd, error ? ERR_PTR(error) : (char *)page); 174 return NULL; 175 } 176 177 static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) 178 { 179 char *page = nd_get_link(nd); 180 if (!IS_ERR(page)) 181 free_page((unsigned long)page); 182 } 183 184 const struct inode_operations sysfs_symlink_inode_operations = { 185 .readlink = generic_readlink, 186 .follow_link = sysfs_follow_link, 187 .put_link = sysfs_put_link, 188 }; 189 190 191 EXPORT_SYMBOL_GPL(sysfs_create_link); 192 EXPORT_SYMBOL_GPL(sysfs_remove_link); 193