Blame view

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