Blame view

fs/configfs/symlink.c 7.19 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
  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;
56d10194b   Guenter Roeck   configfs: replace...
65
  		memcpy(buffer + length, config_item_name(p), cur);
7063fbf22   Joel Becker   [PATCH] configfs:...
66
67
68
69
70
  		*(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
  	ret = -ENOMEM;
  	sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
  	if (sl) {
5301a77da   Louis Rilling   configfs: Protect...
83
  		spin_lock(&configfs_dirent_lock);
4768e9b18   Louis Rilling   [PATCH] configfs:...
84
85
  		if (target_sd->s_type & CONFIGFS_USET_DROPPING) {
  			spin_unlock(&configfs_dirent_lock);
4768e9b18   Louis Rilling   [PATCH] configfs:...
86
87
88
  			kfree(sl);
  			return -ENOENT;
  		}
ba80aa909   Nicholas Bellinger   configfs: Fix rac...
89
  		sl->sl_target = config_item_get(item);
7063fbf22   Joel Becker   [PATCH] configfs:...
90
  		list_add(&sl->sl_list, &target_sd->s_links);
5301a77da   Louis Rilling   configfs: Protect...
91
  		spin_unlock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
92
93
94
  		ret = configfs_create_link(sl, parent_item->ci_dentry,
  					   dentry);
  		if (ret) {
5301a77da   Louis Rilling   configfs: Protect...
95
  			spin_lock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
96
  			list_del_init(&sl->sl_list);
5301a77da   Louis Rilling   configfs: Protect...
97
  			spin_unlock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
98
99
100
101
  			config_item_put(item);
  			kfree(sl);
  		}
  	}
2a109f2a4   Louis Rilling   [PATCH] configfs:...
102
  out:
7063fbf22   Joel Becker   [PATCH] configfs:...
103
104
  	return ret;
  }
421748ecd   Al Viro   [PATCH] assorted ...
105
  static int get_target(const char *symname, struct path *path,
b7c177fcd   Al Viro   configfs: kill co...
106
  		      struct config_item **target, struct super_block *sb)
7063fbf22   Joel Becker   [PATCH] configfs:...
107
108
  {
  	int ret;
421748ecd   Al Viro   [PATCH] assorted ...
109
  	ret = kern_path(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, path);
7063fbf22   Joel Becker   [PATCH] configfs:...
110
  	if (!ret) {
b7c177fcd   Al Viro   configfs: kill co...
111
  		if (path->dentry->d_sb == sb) {
421748ecd   Al Viro   [PATCH] assorted ...
112
  			*target = configfs_get_config_item(path->dentry);
7063fbf22   Joel Becker   [PATCH] configfs:...
113
114
  			if (!*target) {
  				ret = -ENOENT;
421748ecd   Al Viro   [PATCH] assorted ...
115
  				path_put(path);
7063fbf22   Joel Becker   [PATCH] configfs:...
116
  			}
9b6e31021   Al Viro   Fix configfs leak
117
  		} else {
7063fbf22   Joel Becker   [PATCH] configfs:...
118
  			ret = -EPERM;
9b6e31021   Al Viro   Fix configfs leak
119
120
  			path_put(path);
  		}
7063fbf22   Joel Becker   [PATCH] configfs:...
121
122
123
124
125
126
127
128
129
  	}
  
  	return ret;
  }
  
  
  int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
  {
  	int ret;
421748ecd   Al Viro   [PATCH] assorted ...
130
  	struct path path;
2a109f2a4   Louis Rilling   [PATCH] configfs:...
131
  	struct configfs_dirent *sd;
7063fbf22   Joel Becker   [PATCH] configfs:...
132
  	struct config_item *parent_item;
3c48f23ad   Subrata Modak   configfs: Fix Tri...
133
  	struct config_item *target_item = NULL;
7063fbf22   Joel Becker   [PATCH] configfs:...
134
  	struct config_item_type *type;
2a109f2a4   Louis Rilling   [PATCH] configfs:...
135
136
137
138
139
140
141
142
  	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:...
143
144
  	parent_item = configfs_get_config_item(dentry->d_parent);
  	type = parent_item->ci_type;
2a109f2a4   Louis Rilling   [PATCH] configfs:...
145
  	ret = -EPERM;
7063fbf22   Joel Becker   [PATCH] configfs:...
146
147
148
  	if (!type || !type->ct_item_ops ||
  	    !type->ct_item_ops->allow_link)
  		goto out_put;
b7c177fcd   Al Viro   configfs: kill co...
149
  	ret = get_target(symname, &path, &target_item, dentry->d_sb);
7063fbf22   Joel Becker   [PATCH] configfs:...
150
151
152
153
  	if (ret)
  		goto out_put;
  
  	ret = type->ct_item_ops->allow_link(parent_item, target_item);
e75206517   Louis Rilling   configfs: call dr...
154
  	if (!ret) {
9a73d78cd   Louis Rilling   [PATCH] configfs:...
155
  		mutex_lock(&configfs_symlink_mutex);
7063fbf22   Joel Becker   [PATCH] configfs:...
156
  		ret = create_link(parent_item, target_item, dentry);
9a73d78cd   Louis Rilling   [PATCH] configfs:...
157
  		mutex_unlock(&configfs_symlink_mutex);
e75206517   Louis Rilling   configfs: call dr...
158
159
160
161
  		if (ret && type->ct_item_ops->drop_link)
  			type->ct_item_ops->drop_link(parent_item,
  						     target_item);
  	}
7063fbf22   Joel Becker   [PATCH] configfs:...
162
163
  
  	config_item_put(target_item);
421748ecd   Al Viro   [PATCH] assorted ...
164
  	path_put(&path);
7063fbf22   Joel Becker   [PATCH] configfs:...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  
  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;
7063fbf22   Joel Becker   [PATCH] configfs:...
184
185
186
187
  	sl = sd->s_element;
  
  	parent_item = configfs_get_config_item(dentry->d_parent);
  	type = parent_item->ci_type;
6f6107640   Louis Rilling   configfs: Introdu...
188
  	spin_lock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
189
  	list_del_init(&sd->s_sibling);
6f6107640   Louis Rilling   configfs: Introdu...
190
  	spin_unlock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
191
192
193
194
195
196
197
198
199
200
201
202
203
  	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...
204
  	spin_lock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
205
  	list_del_init(&sl->sl_list);
5301a77da   Louis Rilling   configfs: Protect...
206
  	spin_unlock(&configfs_dirent_lock);
7063fbf22   Joel Becker   [PATCH] configfs:...
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  
  	/* 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...
230
231
  	pr_debug("%s: depth = %d, size = %d
  ", __func__, depth, size);
7063fbf22   Joel Becker   [PATCH] configfs:...
232
233
234
235
236
  
  	for (s = path; depth--; s += 3)
  		strcpy(s,"../");
  
  	fill_item_path(target, path, size);
8e24eea72   Harvey Harrison   fs: replace remai...
237
238
  	pr_debug("%s: path = '%s'
  ", __func__, path);
7063fbf22   Joel Becker   [PATCH] configfs:...
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  
  	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;
  
  }
6b2553918   Al Viro   replace ->follow_...
267
  static const char *configfs_get_link(struct dentry *dentry,
fceef393a   Al Viro   switch ->get_link...
268
269
  				     struct inode *inode,
  				     struct delayed_call *done)
7063fbf22   Joel Becker   [PATCH] configfs:...
270
  {
fceef393a   Al Viro   switch ->get_link...
271
  	char *body;
680baacbc   Al Viro   new ->follow_link...
272
  	int error;
7063fbf22   Joel Becker   [PATCH] configfs:...
273

6b2553918   Al Viro   replace ->follow_...
274
275
  	if (!dentry)
  		return ERR_PTR(-ECHILD);
fceef393a   Al Viro   switch ->get_link...
276
277
  	body = kzalloc(PAGE_SIZE, GFP_KERNEL);
  	if (!body)
680baacbc   Al Viro   new ->follow_link...
278
  		return ERR_PTR(-ENOMEM);
fceef393a   Al Viro   switch ->get_link...
279
  	error = configfs_getlink(dentry, body);
680baacbc   Al Viro   new ->follow_link...
280
  	if (!error) {
fceef393a   Al Viro   switch ->get_link...
281
282
  		set_delayed_call(done, kfree_link, body);
  		return body;
7063fbf22   Joel Becker   [PATCH] configfs:...
283
  	}
fceef393a   Al Viro   switch ->get_link...
284
  	kfree(body);
680baacbc   Al Viro   new ->follow_link...
285
  	return ERR_PTR(error);
7063fbf22   Joel Becker   [PATCH] configfs:...
286
  }
754661f14   Arjan van de Ven   [PATCH] mark stru...
287
  const struct inode_operations configfs_symlink_inode_operations = {
6b2553918   Al Viro   replace ->follow_...
288
  	.get_link = configfs_get_link,
3d0f89bb1   Joel Becker   configfs: Add per...
289
  	.setattr = configfs_setattr,
7063fbf22   Joel Becker   [PATCH] configfs:...
290
  };