Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
symlink.c
Go to the documentation of this file.
1 /* -*- mode: c; c-basic-offset: 8; -*-
2  * vim: noexpandtab sw=8 ts=8 sts=0:
3  *
4  * symlink.c - operations for configfs symlinks.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA.
20  *
21  * Based on sysfs:
22  * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel
23  *
24  * configfs Copyright (C) 2005 Oracle. All rights reserved.
25  */
26 
27 #include <linux/fs.h>
28 #include <linux/module.h>
29 #include <linux/namei.h>
30 #include <linux/slab.h>
31 
32 #include <linux/configfs.h>
33 #include "configfs_internal.h"
34 
35 /* Protects attachments of new symlinks */
36 DEFINE_MUTEX(configfs_symlink_mutex);
37 
38 static int item_depth(struct config_item * item)
39 {
40  struct config_item * p = item;
41  int depth = 0;
42  do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
43  return depth;
44 }
45 
46 static int item_path_length(struct config_item * item)
47 {
48  struct config_item * p = item;
49  int length = 1;
50  do {
51  length += strlen(config_item_name(p)) + 1;
52  p = p->ci_parent;
53  } while (p && !configfs_is_root(p));
54  return length;
55 }
56 
57 static void fill_item_path(struct config_item * item, char * buffer, int length)
58 {
59  struct config_item * p;
60 
61  --length;
62  for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
63  int cur = strlen(config_item_name(p));
64 
65  /* back up enough to print this bus id with '/' */
66  length -= cur;
67  strncpy(buffer + length,config_item_name(p),cur);
68  *(buffer + --length) = '/';
69  }
70 }
71 
72 static int create_link(struct config_item *parent_item,
73  struct config_item *item,
74  struct dentry *dentry)
75 {
76  struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
77  struct configfs_symlink *sl;
78  int ret;
79 
80  ret = -ENOENT;
81  if (!configfs_dirent_is_ready(target_sd))
82  goto out;
83  ret = -ENOMEM;
84  sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
85  if (sl) {
86  sl->sl_target = config_item_get(item);
87  spin_lock(&configfs_dirent_lock);
88  if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
89  spin_unlock(&configfs_dirent_lock);
90  config_item_put(item);
91  kfree(sl);
92  return -ENOENT;
93  }
94  list_add(&sl->sl_list, &target_sd->s_links);
95  spin_unlock(&configfs_dirent_lock);
96  ret = configfs_create_link(sl, parent_item->ci_dentry,
97  dentry);
98  if (ret) {
99  spin_lock(&configfs_dirent_lock);
100  list_del_init(&sl->sl_list);
101  spin_unlock(&configfs_dirent_lock);
102  config_item_put(item);
103  kfree(sl);
104  }
105  }
106 
107 out:
108  return ret;
109 }
110 
111 
112 static int get_target(const char *symname, struct path *path,
113  struct config_item **target, struct super_block *sb)
114 {
115  int ret;
116 
117  ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
118  if (!ret) {
119  if (path->dentry->d_sb == sb) {
120  *target = configfs_get_config_item(path->dentry);
121  if (!*target) {
122  ret = -ENOENT;
123  path_put(path);
124  }
125  } else {
126  ret = -EPERM;
127  path_put(path);
128  }
129  }
130 
131  return ret;
132 }
133 
134 
135 int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
136 {
137  int ret;
138  struct path path;
139  struct configfs_dirent *sd;
140  struct config_item *parent_item;
141  struct config_item *target_item = NULL;
142  struct config_item_type *type;
143 
144  sd = dentry->d_parent->d_fsdata;
145  /*
146  * Fake invisibility if dir belongs to a group/default groups hierarchy
147  * being attached
148  */
149  ret = -ENOENT;
150  if (!configfs_dirent_is_ready(sd))
151  goto out;
152 
153  parent_item = configfs_get_config_item(dentry->d_parent);
154  type = parent_item->ci_type;
155 
156  ret = -EPERM;
157  if (!type || !type->ct_item_ops ||
158  !type->ct_item_ops->allow_link)
159  goto out_put;
160 
161  ret = get_target(symname, &path, &target_item, dentry->d_sb);
162  if (ret)
163  goto out_put;
164 
165  ret = type->ct_item_ops->allow_link(parent_item, target_item);
166  if (!ret) {
168  ret = create_link(parent_item, target_item, dentry);
170  if (ret && type->ct_item_ops->drop_link)
171  type->ct_item_ops->drop_link(parent_item,
172  target_item);
173  }
174 
175  config_item_put(target_item);
176  path_put(&path);
177 
178 out_put:
179  config_item_put(parent_item);
180 
181 out:
182  return ret;
183 }
184 
185 int configfs_unlink(struct inode *dir, struct dentry *dentry)
186 {
187  struct configfs_dirent *sd = dentry->d_fsdata;
188  struct configfs_symlink *sl;
189  struct config_item *parent_item;
190  struct config_item_type *type;
191  int ret;
192 
193  ret = -EPERM; /* What lack-of-symlink returns */
194  if (!(sd->s_type & CONFIGFS_ITEM_LINK))
195  goto out;
196 
197  sl = sd->s_element;
198 
199  parent_item = configfs_get_config_item(dentry->d_parent);
200  type = parent_item->ci_type;
201 
202  spin_lock(&configfs_dirent_lock);
203  list_del_init(&sd->s_sibling);
204  spin_unlock(&configfs_dirent_lock);
205  configfs_drop_dentry(sd, dentry->d_parent);
206  dput(dentry);
207  configfs_put(sd);
208 
209  /*
210  * drop_link() must be called before
211  * list_del_init(&sl->sl_list), so that the order of
212  * drop_link(this, target) and drop_item(target) is preserved.
213  */
214  if (type && type->ct_item_ops &&
215  type->ct_item_ops->drop_link)
216  type->ct_item_ops->drop_link(parent_item,
217  sl->sl_target);
218 
219  spin_lock(&configfs_dirent_lock);
220  list_del_init(&sl->sl_list);
221  spin_unlock(&configfs_dirent_lock);
222 
223  /* Put reference from create_link() */
225  kfree(sl);
226 
227  config_item_put(parent_item);
228 
229  ret = 0;
230 
231 out:
232  return ret;
233 }
234 
235 static int configfs_get_target_path(struct config_item * item, struct config_item * target,
236  char *path)
237 {
238  char * s;
239  int depth, size;
240 
241  depth = item_depth(item);
242  size = item_path_length(target) + depth * 3 - 1;
243  if (size > PATH_MAX)
244  return -ENAMETOOLONG;
245 
246  pr_debug("%s: depth = %d, size = %d\n", __func__, depth, size);
247 
248  for (s = path; depth--; s += 3)
249  strcpy(s,"../");
250 
251  fill_item_path(target, path, size);
252  pr_debug("%s: path = '%s'\n", __func__, path);
253 
254  return 0;
255 }
256 
257 static int configfs_getlink(struct dentry *dentry, char * path)
258 {
259  struct config_item *item, *target_item;
260  int error = 0;
261 
262  item = configfs_get_config_item(dentry->d_parent);
263  if (!item)
264  return -EINVAL;
265 
266  target_item = configfs_get_config_item(dentry);
267  if (!target_item) {
268  config_item_put(item);
269  return -EINVAL;
270  }
271 
272  down_read(&configfs_rename_sem);
273  error = configfs_get_target_path(item, target_item, path);
274  up_read(&configfs_rename_sem);
275 
276  config_item_put(item);
277  config_item_put(target_item);
278  return error;
279 
280 }
281 
282 static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
283 {
284  int error = -ENOMEM;
285  unsigned long page = get_zeroed_page(GFP_KERNEL);
286 
287  if (page) {
288  error = configfs_getlink(dentry, (char *)page);
289  if (!error) {
290  nd_set_link(nd, (char *)page);
291  return (void *)page;
292  }
293  }
294 
295  nd_set_link(nd, ERR_PTR(error));
296  return NULL;
297 }
298 
299 static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
300  void *cookie)
301 {
302  if (cookie) {
303  unsigned long page = (unsigned long)cookie;
304  free_page(page);
305  }
306 }
307 
309  .follow_link = configfs_follow_link,
310  .readlink = generic_readlink,
311  .put_link = configfs_put_link,
312  .setattr = configfs_setattr,
313 };
314