aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/configfs')
-rw-r--r--fs/configfs/Makefile7
-rw-r--r--fs/configfs/configfs_internal.h142
-rw-r--r--fs/configfs/dir.c1102
-rw-r--r--fs/configfs/file.c360
-rw-r--r--fs/configfs/inode.c162
-rw-r--r--fs/configfs/item.c227
-rw-r--r--fs/configfs/mount.c159
-rw-r--r--fs/configfs/symlink.c281
8 files changed, 2440 insertions, 0 deletions
diff --git a/fs/configfs/Makefile b/fs/configfs/Makefile
new file mode 100644
index 000000000000..00ffb278e98c
--- /dev/null
+++ b/fs/configfs/Makefile
@@ -0,0 +1,7 @@
1#
2# Makefile for the configfs virtual filesystem
3#
4
5obj-$(CONFIG_CONFIGFS_FS) += configfs.o
6
7configfs-objs := inode.o file.o dir.o symlink.o mount.o item.o
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
new file mode 100644
index 000000000000..8899d9c5f6bf
--- /dev/null
+++ b/fs/configfs/configfs_internal.h
@@ -0,0 +1,142 @@
1/* -*- mode: c; c-basic-offset:8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * configfs_internal.h - Internal stuff for configfs
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/slab.h>
28#include <linux/list.h>
29
30struct configfs_dirent {
31 atomic_t s_count;
32 struct list_head s_sibling;
33 struct list_head s_children;
34 struct list_head s_links;
35 void * s_element;
36 int s_type;
37 umode_t s_mode;
38 struct dentry * s_dentry;
39};
40
41#define CONFIGFS_ROOT 0x0001
42#define CONFIGFS_DIR 0x0002
43#define CONFIGFS_ITEM_ATTR 0x0004
44#define CONFIGFS_ITEM_LINK 0x0020
45#define CONFIGFS_USET_DIR 0x0040
46#define CONFIGFS_USET_DEFAULT 0x0080
47#define CONFIGFS_USET_DROPPING 0x0100
48#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR)
49
50extern struct vfsmount * configfs_mount;
51
52extern int configfs_is_root(struct config_item *item);
53
54extern struct inode * configfs_new_inode(mode_t mode);
55extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *));
56
57extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
58extern int configfs_make_dirent(struct configfs_dirent *,
59 struct dentry *, void *, umode_t, int);
60
61extern int configfs_add_file(struct dentry *, const struct configfs_attribute *, int);
62extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
63
64extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
65extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
66
67extern int configfs_pin_fs(void);
68extern void configfs_release_fs(void);
69
70extern struct rw_semaphore configfs_rename_sem;
71extern struct super_block * configfs_sb;
72extern struct file_operations configfs_dir_operations;
73extern struct file_operations configfs_file_operations;
74extern struct file_operations bin_fops;
75extern struct inode_operations configfs_dir_inode_operations;
76extern struct inode_operations configfs_symlink_inode_operations;
77
78extern int configfs_symlink(struct inode *dir, struct dentry *dentry,
79 const char *symname);
80extern int configfs_unlink(struct inode *dir, struct dentry *dentry);
81
82struct configfs_symlink {
83 struct list_head sl_list;
84 struct config_item *sl_target;
85};
86
87extern int configfs_create_link(struct configfs_symlink *sl,
88 struct dentry *parent,
89 struct dentry *dentry);
90
91static inline struct config_item * to_item(struct dentry * dentry)
92{
93 struct configfs_dirent * sd = dentry->d_fsdata;
94 return ((struct config_item *) sd->s_element);
95}
96
97static inline struct configfs_attribute * to_attr(struct dentry * dentry)
98{
99 struct configfs_dirent * sd = dentry->d_fsdata;
100 return ((struct configfs_attribute *) sd->s_element);
101}
102
103static inline struct config_item *configfs_get_config_item(struct dentry *dentry)
104{
105 struct config_item * item = NULL;
106
107 spin_lock(&dcache_lock);
108 if (!d_unhashed(dentry)) {
109 struct configfs_dirent * sd = dentry->d_fsdata;
110 if (sd->s_type & CONFIGFS_ITEM_LINK) {
111 struct configfs_symlink * sl = sd->s_element;
112 item = config_item_get(sl->sl_target);
113 } else
114 item = config_item_get(sd->s_element);
115 }
116 spin_unlock(&dcache_lock);
117
118 return item;
119}
120
121static inline void release_configfs_dirent(struct configfs_dirent * sd)
122{
123 if (!(sd->s_type & CONFIGFS_ROOT))
124 kfree(sd);
125}
126
127static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd)
128{
129 if (sd) {
130 WARN_ON(!atomic_read(&sd->s_count));
131 atomic_inc(&sd->s_count);
132 }
133 return sd;
134}
135
136static inline void configfs_put(struct configfs_dirent * sd)
137{
138 WARN_ON(!atomic_read(&sd->s_count));
139 if (atomic_dec_and_test(&sd->s_count))
140 release_configfs_dirent(sd);
141}
142
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
new file mode 100644
index 000000000000..e48b539243a1
--- /dev/null
+++ b/fs/configfs/dir.c
@@ -0,0 +1,1102 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * dir.c - Operations for configfs directories.
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#undef DEBUG
28
29#include <linux/fs.h>
30#include <linux/mount.h>
31#include <linux/module.h>
32#include <linux/slab.h>
33
34#include <linux/configfs.h>
35#include "configfs_internal.h"
36
37DECLARE_RWSEM(configfs_rename_sem);
38
39static void configfs_d_iput(struct dentry * dentry,
40 struct inode * inode)
41{
42 struct configfs_dirent * sd = dentry->d_fsdata;
43
44 if (sd) {
45 BUG_ON(sd->s_dentry != dentry);
46 sd->s_dentry = NULL;
47 configfs_put(sd);
48 }
49 iput(inode);
50}
51
52/*
53 * We _must_ delete our dentries on last dput, as the chain-to-parent
54 * behavior is required to clear the parents of default_groups.
55 */
56static int configfs_d_delete(struct dentry *dentry)
57{
58 return 1;
59}
60
61static struct dentry_operations configfs_dentry_ops = {
62 .d_iput = configfs_d_iput,
63 /* simple_delete_dentry() isn't exported */
64 .d_delete = configfs_d_delete,
65};
66
67/*
68 * Allocates a new configfs_dirent and links it to the parent configfs_dirent
69 */
70static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * parent_sd,
71 void * element)
72{
73 struct configfs_dirent * sd;
74
75 sd = kmalloc(sizeof(*sd), GFP_KERNEL);
76 if (!sd)
77 return NULL;
78
79 memset(sd, 0, sizeof(*sd));
80 atomic_set(&sd->s_count, 1);
81 INIT_LIST_HEAD(&sd->s_links);
82 INIT_LIST_HEAD(&sd->s_children);
83 list_add(&sd->s_sibling, &parent_sd->s_children);
84 sd->s_element = element;
85
86 return sd;
87}
88
89int configfs_make_dirent(struct configfs_dirent * parent_sd,
90 struct dentry * dentry, void * element,
91 umode_t mode, int type)
92{
93 struct configfs_dirent * sd;
94
95 sd = configfs_new_dirent(parent_sd, element);
96 if (!sd)
97 return -ENOMEM;
98
99 sd->s_mode = mode;
100 sd->s_type = type;
101 sd->s_dentry = dentry;
102 if (dentry) {
103 dentry->d_fsdata = configfs_get(sd);
104 dentry->d_op = &configfs_dentry_ops;
105 }
106
107 return 0;
108}
109
110static int init_dir(struct inode * inode)
111{
112 inode->i_op = &configfs_dir_inode_operations;
113 inode->i_fop = &configfs_dir_operations;
114
115 /* directory inodes start off with i_nlink == 2 (for "." entry) */
116 inode->i_nlink++;
117 return 0;
118}
119
120static int init_file(struct inode * inode)
121{
122 inode->i_size = PAGE_SIZE;
123 inode->i_fop = &configfs_file_operations;
124 return 0;
125}
126
127static int init_symlink(struct inode * inode)
128{
129 inode->i_op = &configfs_symlink_inode_operations;
130 return 0;
131}
132
133static int create_dir(struct config_item * k, struct dentry * p,
134 struct dentry * d)
135{
136 int error;
137 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
138
139 error = configfs_create(d, mode, init_dir);
140 if (!error) {
141 error = configfs_make_dirent(p->d_fsdata, d, k, mode,
142 CONFIGFS_DIR);
143 if (!error) {
144 p->d_inode->i_nlink++;
145 (d)->d_op = &configfs_dentry_ops;
146 }
147 }
148 return error;
149}
150
151
152/**
153 * configfs_create_dir - create a directory for an config_item.
154 * @item: config_itemwe're creating directory for.
155 * @dentry: config_item's dentry.
156 */
157
158static int configfs_create_dir(struct config_item * item, struct dentry *dentry)
159{
160 struct dentry * parent;
161 int error = 0;
162
163 BUG_ON(!item);
164
165 if (item->ci_parent)
166 parent = item->ci_parent->ci_dentry;
167 else if (configfs_mount && configfs_mount->mnt_sb)
168 parent = configfs_mount->mnt_sb->s_root;
169 else
170 return -EFAULT;
171
172 error = create_dir(item,parent,dentry);
173 if (!error)
174 item->ci_dentry = dentry;
175 return error;
176}
177
178int configfs_create_link(struct configfs_symlink *sl,
179 struct dentry *parent,
180 struct dentry *dentry)
181{
182 int err = 0;
183 umode_t mode = S_IFLNK | S_IRWXUGO;
184
185 err = configfs_create(dentry, mode, init_symlink);
186 if (!err) {
187 err = configfs_make_dirent(parent->d_fsdata, dentry, sl,
188 mode, CONFIGFS_ITEM_LINK);
189 if (!err)
190 dentry->d_op = &configfs_dentry_ops;
191 }
192 return err;
193}
194
195static void remove_dir(struct dentry * d)
196{
197 struct dentry * parent = dget(d->d_parent);
198 struct configfs_dirent * sd;
199
200 sd = d->d_fsdata;
201 list_del_init(&sd->s_sibling);
202 configfs_put(sd);
203 if (d->d_inode)
204 simple_rmdir(parent->d_inode,d);
205
206 pr_debug(" o %s removing done (%d)\n",d->d_name.name,
207 atomic_read(&d->d_count));
208
209 dput(parent);
210}
211
212/**
213 * configfs_remove_dir - remove an config_item's directory.
214 * @item: config_item we're removing.
215 *
216 * The only thing special about this is that we remove any files in
217 * the directory before we remove the directory, and we've inlined
218 * what used to be configfs_rmdir() below, instead of calling separately.
219 */
220
221static void configfs_remove_dir(struct config_item * item)
222{
223 struct dentry * dentry = dget(item->ci_dentry);
224
225 if (!dentry)
226 return;
227
228 remove_dir(dentry);
229 /**
230 * Drop reference from dget() on entrance.
231 */
232 dput(dentry);
233}
234
235
236/* attaches attribute's configfs_dirent to the dentry corresponding to the
237 * attribute file
238 */
239static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry)
240{
241 struct configfs_attribute * attr = sd->s_element;
242 int error;
243
244 error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file);
245 if (error)
246 return error;
247
248 dentry->d_op = &configfs_dentry_ops;
249 dentry->d_fsdata = configfs_get(sd);
250 sd->s_dentry = dentry;
251 d_rehash(dentry);
252
253 return 0;
254}
255
256static struct dentry * configfs_lookup(struct inode *dir,
257 struct dentry *dentry,
258 struct nameidata *nd)
259{
260 struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
261 struct configfs_dirent * sd;
262 int found = 0;
263 int err = 0;
264
265 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
266 if (sd->s_type & CONFIGFS_NOT_PINNED) {
267 const unsigned char * name = configfs_get_name(sd);
268
269 if (strcmp(name, dentry->d_name.name))
270 continue;
271
272 found = 1;
273 err = configfs_attach_attr(sd, dentry);
274 break;
275 }
276 }
277
278 if (!found) {
279 /*
280 * If it doesn't exist and it isn't a NOT_PINNED item,
281 * it must be negative.
282 */
283 return simple_lookup(dir, dentry, nd);
284 }
285
286 return ERR_PTR(err);
287}
288
289/*
290 * Only subdirectories count here. Files (CONFIGFS_NOT_PINNED) are
291 * attributes and are removed by rmdir(). We recurse, taking i_sem
292 * on all children that are candidates for default detach. If the
293 * result is clean, then configfs_detach_group() will handle dropping
294 * i_sem. If there is an error, the caller will clean up the i_sem
295 * holders via configfs_detach_rollback().
296 */
297static int configfs_detach_prep(struct dentry *dentry)
298{
299 struct configfs_dirent *parent_sd = dentry->d_fsdata;
300 struct configfs_dirent *sd;
301 int ret;
302
303 ret = -EBUSY;
304 if (!list_empty(&parent_sd->s_links))
305 goto out;
306
307 ret = 0;
308 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
309 if (sd->s_type & CONFIGFS_NOT_PINNED)
310 continue;
311 if (sd->s_type & CONFIGFS_USET_DEFAULT) {
312 down(&sd->s_dentry->d_inode->i_sem);
313 /* Mark that we've taken i_sem */
314 sd->s_type |= CONFIGFS_USET_DROPPING;
315
316 ret = configfs_detach_prep(sd->s_dentry);
317 if (!ret)
318 continue;
319 } else
320 ret = -ENOTEMPTY;
321
322 break;
323 }
324
325out:
326 return ret;
327}
328
329/*
330 * Walk the tree, dropping i_sem wherever CONFIGFS_USET_DROPPING is
331 * set.
332 */
333static void configfs_detach_rollback(struct dentry *dentry)
334{
335 struct configfs_dirent *parent_sd = dentry->d_fsdata;
336 struct configfs_dirent *sd;
337
338 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
339 if (sd->s_type & CONFIGFS_USET_DEFAULT) {
340 configfs_detach_rollback(sd->s_dentry);
341
342 if (sd->s_type & CONFIGFS_USET_DROPPING) {
343 sd->s_type &= ~CONFIGFS_USET_DROPPING;
344 up(&sd->s_dentry->d_inode->i_sem);
345 }
346 }
347 }
348}
349
350static void detach_attrs(struct config_item * item)
351{
352 struct dentry * dentry = dget(item->ci_dentry);
353 struct configfs_dirent * parent_sd;
354 struct configfs_dirent * sd, * tmp;
355
356 if (!dentry)
357 return;
358
359 pr_debug("configfs %s: dropping attrs for dir\n",
360 dentry->d_name.name);
361
362 parent_sd = dentry->d_fsdata;
363 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
364 if (!sd->s_element || !(sd->s_type & CONFIGFS_NOT_PINNED))
365 continue;
366 list_del_init(&sd->s_sibling);
367 configfs_drop_dentry(sd, dentry);
368 configfs_put(sd);
369 }
370
371 /**
372 * Drop reference from dget() on entrance.
373 */
374 dput(dentry);
375}
376
377static int populate_attrs(struct config_item *item)
378{
379 struct config_item_type *t = item->ci_type;
380 struct configfs_attribute *attr;
381 int error = 0;
382 int i;
383
384 if (!t)
385 return -EINVAL;
386 if (t->ct_attrs) {
387 for (i = 0; (attr = t->ct_attrs[i]) != NULL; i++) {
388 if ((error = configfs_create_file(item, attr)))
389 break;
390 }
391 }
392
393 if (error)
394 detach_attrs(item);
395
396 return error;
397}
398
399static int configfs_attach_group(struct config_item *parent_item,
400 struct config_item *item,
401 struct dentry *dentry);
402static void configfs_detach_group(struct config_item *item);
403
404static void detach_groups(struct config_group *group)
405{
406 struct dentry * dentry = dget(group->cg_item.ci_dentry);
407 struct dentry *child;
408 struct configfs_dirent *parent_sd;
409 struct configfs_dirent *sd, *tmp;
410
411 if (!dentry)
412 return;
413
414 parent_sd = dentry->d_fsdata;
415 list_for_each_entry_safe(sd, tmp, &parent_sd->s_children, s_sibling) {
416 if (!sd->s_element ||
417 !(sd->s_type & CONFIGFS_USET_DEFAULT))
418 continue;
419
420 child = sd->s_dentry;
421
422 configfs_detach_group(sd->s_element);
423 child->d_inode->i_flags |= S_DEAD;
424
425 /*
426 * From rmdir/unregister, a configfs_detach_prep() pass
427 * has taken our i_sem for us. Drop it.
428 * From mkdir/register cleanup, there is no sem held.
429 */
430 if (sd->s_type & CONFIGFS_USET_DROPPING)
431 up(&child->d_inode->i_sem);
432
433 d_delete(child);
434 dput(child);
435 }
436
437 /**
438 * Drop reference from dget() on entrance.
439 */
440 dput(dentry);
441}
442
443/*
444 * This fakes mkdir(2) on a default_groups[] entry. It
445 * creates a dentry, attachs it, and then does fixup
446 * on the sd->s_type.
447 *
448 * We could, perhaps, tweak our parent's ->mkdir for a minute and
449 * try using vfs_mkdir. Just a thought.
450 */
451static int create_default_group(struct config_group *parent_group,
452 struct config_group *group)
453{
454 int ret;
455 struct qstr name;
456 struct configfs_dirent *sd;
457 /* We trust the caller holds a reference to parent */
458 struct dentry *child, *parent = parent_group->cg_item.ci_dentry;
459
460 if (!group->cg_item.ci_name)
461 group->cg_item.ci_name = group->cg_item.ci_namebuf;
462 name.name = group->cg_item.ci_name;
463 name.len = strlen(name.name);
464 name.hash = full_name_hash(name.name, name.len);
465
466 ret = -ENOMEM;
467 child = d_alloc(parent, &name);
468 if (child) {
469 d_add(child, NULL);
470
471 ret = configfs_attach_group(&parent_group->cg_item,
472 &group->cg_item, child);
473 if (!ret) {
474 sd = child->d_fsdata;
475 sd->s_type |= CONFIGFS_USET_DEFAULT;
476 } else {
477 d_delete(child);
478 dput(child);
479 }
480 }
481
482 return ret;
483}
484
485static int populate_groups(struct config_group *group)
486{
487 struct config_group *new_group;
488 struct dentry *dentry = group->cg_item.ci_dentry;
489 int ret = 0;
490 int i;
491
492 if (group && group->default_groups) {
493 /* FYI, we're faking mkdir here
494 * I'm not sure we need this semaphore, as we're called
495 * from our parent's mkdir. That holds our parent's
496 * i_sem, so afaik lookup cannot continue through our
497 * parent to find us, let alone mess with our tree.
498 * That said, taking our i_sem is closer to mkdir
499 * emulation, and shouldn't hurt. */
500 down(&dentry->d_inode->i_sem);
501
502 for (i = 0; group->default_groups[i]; i++) {
503 new_group = group->default_groups[i];
504
505 ret = create_default_group(group, new_group);
506 if (ret)
507 break;
508 }
509
510 up(&dentry->d_inode->i_sem);
511 }
512
513 if (ret)
514 detach_groups(group);
515
516 return ret;
517}
518
519/*
520 * All of link_obj/unlink_obj/link_group/unlink_group require that
521 * subsys->su_sem is held.
522 */
523
524static void unlink_obj(struct config_item *item)
525{
526 struct config_group *group;
527
528 group = item->ci_group;
529 if (group) {
530 list_del_init(&item->ci_entry);
531
532 item->ci_group = NULL;
533 item->ci_parent = NULL;
534 config_item_put(item);
535
536 config_group_put(group);
537 }
538}
539
540static void link_obj(struct config_item *parent_item, struct config_item *item)
541{
542 /* Parent seems redundant with group, but it makes certain
543 * traversals much nicer. */
544 item->ci_parent = parent_item;
545 item->ci_group = config_group_get(to_config_group(parent_item));
546 list_add_tail(&item->ci_entry, &item->ci_group->cg_children);
547
548 config_item_get(item);
549}
550
551static void unlink_group(struct config_group *group)
552{
553 int i;
554 struct config_group *new_group;
555
556 if (group->default_groups) {
557 for (i = 0; group->default_groups[i]; i++) {
558 new_group = group->default_groups[i];
559 unlink_group(new_group);
560 }
561 }
562
563 group->cg_subsys = NULL;
564 unlink_obj(&group->cg_item);
565}
566
567static void link_group(struct config_group *parent_group, struct config_group *group)
568{
569 int i;
570 struct config_group *new_group;
571 struct configfs_subsystem *subsys = NULL; /* gcc is a turd */
572
573 link_obj(&parent_group->cg_item, &group->cg_item);
574
575 if (parent_group->cg_subsys)
576 subsys = parent_group->cg_subsys;
577 else if (configfs_is_root(&parent_group->cg_item))
578 subsys = to_configfs_subsystem(group);
579 else
580 BUG();
581 group->cg_subsys = subsys;
582
583 if (group->default_groups) {
584 for (i = 0; group->default_groups[i]; i++) {
585 new_group = group->default_groups[i];
586 link_group(group, new_group);
587 }
588 }
589}
590
591/*
592 * The goal is that configfs_attach_item() (and
593 * configfs_attach_group()) can be called from either the VFS or this
594 * module. That is, they assume that the items have been created,
595 * the dentry allocated, and the dcache is all ready to go.
596 *
597 * If they fail, they must clean up after themselves as if they
598 * had never been called. The caller (VFS or local function) will
599 * handle cleaning up the dcache bits.
600 *
601 * configfs_detach_group() and configfs_detach_item() behave similarly on
602 * the way out. They assume that the proper semaphores are held, they
603 * clean up the configfs items, and they expect their callers will
604 * handle the dcache bits.
605 */
606static int configfs_attach_item(struct config_item *parent_item,
607 struct config_item *item,
608 struct dentry *dentry)
609{
610 int ret;
611
612 ret = configfs_create_dir(item, dentry);
613 if (!ret) {
614 ret = populate_attrs(item);
615 if (ret) {
616 configfs_remove_dir(item);
617 d_delete(dentry);
618 }
619 }
620
621 return ret;
622}
623
624static void configfs_detach_item(struct config_item *item)
625{
626 detach_attrs(item);
627 configfs_remove_dir(item);
628}
629
630static int configfs_attach_group(struct config_item *parent_item,
631 struct config_item *item,
632 struct dentry *dentry)
633{
634 int ret;
635 struct configfs_dirent *sd;
636
637 ret = configfs_attach_item(parent_item, item, dentry);
638 if (!ret) {
639 sd = dentry->d_fsdata;
640 sd->s_type |= CONFIGFS_USET_DIR;
641
642 ret = populate_groups(to_config_group(item));
643 if (ret) {
644 configfs_detach_item(item);
645 d_delete(dentry);
646 }
647 }
648
649 return ret;
650}
651
652static void configfs_detach_group(struct config_item *item)
653{
654 detach_groups(to_config_group(item));
655 configfs_detach_item(item);
656}
657
658/*
659 * Drop the initial reference from make_item()/make_group()
660 * This function assumes that reference is held on item
661 * and that item holds a valid reference to the parent. Also, it
662 * assumes the caller has validated ci_type.
663 */
664static void client_drop_item(struct config_item *parent_item,
665 struct config_item *item)
666{
667 struct config_item_type *type;
668
669 type = parent_item->ci_type;
670 BUG_ON(!type);
671
672 if (type->ct_group_ops && type->ct_group_ops->drop_item)
673 type->ct_group_ops->drop_item(to_config_group(parent_item),
674 item);
675 else
676 config_item_put(item);
677}
678
679
680static int configfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
681{
682 int ret;
683 struct config_group *group;
684 struct config_item *item;
685 struct config_item *parent_item;
686 struct configfs_subsystem *subsys;
687 struct configfs_dirent *sd;
688 struct config_item_type *type;
689 struct module *owner;
690 char *name;
691
692 if (dentry->d_parent == configfs_sb->s_root)
693 return -EPERM;
694
695 sd = dentry->d_parent->d_fsdata;
696 if (!(sd->s_type & CONFIGFS_USET_DIR))
697 return -EPERM;
698
699 parent_item = configfs_get_config_item(dentry->d_parent);
700 type = parent_item->ci_type;
701 subsys = to_config_group(parent_item)->cg_subsys;
702 BUG_ON(!subsys);
703
704 if (!type || !type->ct_group_ops ||
705 (!type->ct_group_ops->make_group &&
706 !type->ct_group_ops->make_item)) {
707 config_item_put(parent_item);
708 return -EPERM; /* What lack-of-mkdir returns */
709 }
710
711 name = kmalloc(dentry->d_name.len + 1, GFP_KERNEL);
712 if (!name) {
713 config_item_put(parent_item);
714 return -ENOMEM;
715 }
716 snprintf(name, dentry->d_name.len + 1, "%s", dentry->d_name.name);
717
718 down(&subsys->su_sem);
719 group = NULL;
720 item = NULL;
721 if (type->ct_group_ops->make_group) {
722 group = type->ct_group_ops->make_group(to_config_group(parent_item), name);
723 if (group) {
724 link_group(to_config_group(parent_item), group);
725 item = &group->cg_item;
726 }
727 } else {
728 item = type->ct_group_ops->make_item(to_config_group(parent_item), name);
729 if (item)
730 link_obj(parent_item, item);
731 }
732 up(&subsys->su_sem);
733
734 kfree(name);
735 if (!item) {
736 config_item_put(parent_item);
737 return -ENOMEM;
738 }
739
740 ret = -EINVAL;
741 type = item->ci_type;
742 if (type) {
743 owner = type->ct_owner;
744 if (try_module_get(owner)) {
745 if (group) {
746 ret = configfs_attach_group(parent_item,
747 item,
748 dentry);
749 } else {
750 ret = configfs_attach_item(parent_item,
751 item,
752 dentry);
753 }
754
755 if (ret) {
756 down(&subsys->su_sem);
757 if (group)
758 unlink_group(group);
759 else
760 unlink_obj(item);
761 client_drop_item(parent_item, item);
762 up(&subsys->su_sem);
763
764 config_item_put(parent_item);
765 module_put(owner);
766 }
767 }
768 }
769
770 return ret;
771}
772
773static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
774{
775 struct config_item *parent_item;
776 struct config_item *item;
777 struct configfs_subsystem *subsys;
778 struct configfs_dirent *sd;
779 struct module *owner = NULL;
780 int ret;
781
782 if (dentry->d_parent == configfs_sb->s_root)
783 return -EPERM;
784
785 sd = dentry->d_fsdata;
786 if (sd->s_type & CONFIGFS_USET_DEFAULT)
787 return -EPERM;
788
789 parent_item = configfs_get_config_item(dentry->d_parent);
790 subsys = to_config_group(parent_item)->cg_subsys;
791 BUG_ON(!subsys);
792
793 if (!parent_item->ci_type) {
794 config_item_put(parent_item);
795 return -EINVAL;
796 }
797
798 ret = configfs_detach_prep(dentry);
799 if (ret) {
800 configfs_detach_rollback(dentry);
801 config_item_put(parent_item);
802 return ret;
803 }
804
805 item = configfs_get_config_item(dentry);
806
807 /* Drop reference from above, item already holds one. */
808 config_item_put(parent_item);
809
810 if (item->ci_type)
811 owner = item->ci_type->ct_owner;
812
813 if (sd->s_type & CONFIGFS_USET_DIR) {
814 configfs_detach_group(item);
815
816 down(&subsys->su_sem);
817 unlink_group(to_config_group(item));
818 } else {
819 configfs_detach_item(item);
820
821 down(&subsys->su_sem);
822 unlink_obj(item);
823 }
824
825 client_drop_item(parent_item, item);
826 up(&subsys->su_sem);
827
828 /* Drop our reference from above */
829 config_item_put(item);
830
831 module_put(owner);
832
833 return 0;
834}
835
836struct inode_operations configfs_dir_inode_operations = {
837 .mkdir = configfs_mkdir,
838 .rmdir = configfs_rmdir,
839 .symlink = configfs_symlink,
840 .unlink = configfs_unlink,
841 .lookup = configfs_lookup,
842};
843
844#if 0
845int configfs_rename_dir(struct config_item * item, const char *new_name)
846{
847 int error = 0;
848 struct dentry * new_dentry, * parent;
849
850 if (!strcmp(config_item_name(item), new_name))
851 return -EINVAL;
852
853 if (!item->parent)
854 return -EINVAL;
855
856 down_write(&configfs_rename_sem);
857 parent = item->parent->dentry;
858
859 down(&parent->d_inode->i_sem);
860
861 new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
862 if (!IS_ERR(new_dentry)) {
863 if (!new_dentry->d_inode) {
864 error = config_item_set_name(item, "%s", new_name);
865 if (!error) {
866 d_add(new_dentry, NULL);
867 d_move(item->dentry, new_dentry);
868 }
869 else
870 d_delete(new_dentry);
871 } else
872 error = -EEXIST;
873 dput(new_dentry);
874 }
875 up(&parent->d_inode->i_sem);
876 up_write(&configfs_rename_sem);
877
878 return error;
879}
880#endif
881
882static int configfs_dir_open(struct inode *inode, struct file *file)
883{
884 struct dentry * dentry = file->f_dentry;
885 struct configfs_dirent * parent_sd = dentry->d_fsdata;
886
887 down(&dentry->d_inode->i_sem);
888 file->private_data = configfs_new_dirent(parent_sd, NULL);
889 up(&dentry->d_inode->i_sem);
890
891 return file->private_data ? 0 : -ENOMEM;
892
893}
894
895static int configfs_dir_close(struct inode *inode, struct file *file)
896{
897 struct dentry * dentry = file->f_dentry;
898 struct configfs_dirent * cursor = file->private_data;
899
900 down(&dentry->d_inode->i_sem);
901 list_del_init(&cursor->s_sibling);
902 up(&dentry->d_inode->i_sem);
903
904 release_configfs_dirent(cursor);
905
906 return 0;
907}
908
909/* Relationship between s_mode and the DT_xxx types */
910static inline unsigned char dt_type(struct configfs_dirent *sd)
911{
912 return (sd->s_mode >> 12) & 15;
913}
914
915static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
916{
917 struct dentry *dentry = filp->f_dentry;
918 struct configfs_dirent * parent_sd = dentry->d_fsdata;
919 struct configfs_dirent *cursor = filp->private_data;
920 struct list_head *p, *q = &cursor->s_sibling;
921 ino_t ino;
922 int i = filp->f_pos;
923
924 switch (i) {
925 case 0:
926 ino = dentry->d_inode->i_ino;
927 if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0)
928 break;
929 filp->f_pos++;
930 i++;
931 /* fallthrough */
932 case 1:
933 ino = parent_ino(dentry);
934 if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0)
935 break;
936 filp->f_pos++;
937 i++;
938 /* fallthrough */
939 default:
940 if (filp->f_pos == 2) {
941 list_del(q);
942 list_add(q, &parent_sd->s_children);
943 }
944 for (p=q->next; p!= &parent_sd->s_children; p=p->next) {
945 struct configfs_dirent *next;
946 const char * name;
947 int len;
948
949 next = list_entry(p, struct configfs_dirent,
950 s_sibling);
951 if (!next->s_element)
952 continue;
953
954 name = configfs_get_name(next);
955 len = strlen(name);
956 if (next->s_dentry)
957 ino = next->s_dentry->d_inode->i_ino;
958 else
959 ino = iunique(configfs_sb, 2);
960
961 if (filldir(dirent, name, len, filp->f_pos, ino,
962 dt_type(next)) < 0)
963 return 0;
964
965 list_del(q);
966 list_add(q, p);
967 p = q;
968 filp->f_pos++;
969 }
970 }
971 return 0;
972}
973
974static loff_t configfs_dir_lseek(struct file * file, loff_t offset, int origin)
975{
976 struct dentry * dentry = file->f_dentry;
977
978 down(&dentry->d_inode->i_sem);
979 switch (origin) {
980 case 1:
981 offset += file->f_pos;
982 case 0:
983 if (offset >= 0)
984 break;
985 default:
986 up(&file->f_dentry->d_inode->i_sem);
987 return -EINVAL;
988 }
989 if (offset != file->f_pos) {
990 file->f_pos = offset;
991 if (file->f_pos >= 2) {
992 struct configfs_dirent *sd = dentry->d_fsdata;
993 struct configfs_dirent *cursor = file->private_data;
994 struct list_head *p;
995 loff_t n = file->f_pos - 2;
996
997 list_del(&cursor->s_sibling);
998 p = sd->s_children.next;
999 while (n && p != &sd->s_children) {
1000 struct configfs_dirent *next;
1001 next = list_entry(p, struct configfs_dirent,
1002 s_sibling);
1003 if (next->s_element)
1004 n--;
1005 p = p->next;
1006 }
1007 list_add_tail(&cursor->s_sibling, p);
1008 }
1009 }
1010 up(&dentry->d_inode->i_sem);
1011 return offset;
1012}
1013
1014struct file_operations configfs_dir_operations = {
1015 .open = configfs_dir_open,
1016 .release = configfs_dir_close,
1017 .llseek = configfs_dir_lseek,
1018 .read = generic_read_dir,
1019 .readdir = configfs_readdir,
1020};
1021
1022int configfs_register_subsystem(struct configfs_subsystem *subsys)
1023{
1024 int err;
1025 struct config_group *group = &subsys->su_group;
1026 struct qstr name;
1027 struct dentry *dentry;
1028 struct configfs_dirent *sd;
1029
1030 err = configfs_pin_fs();
1031 if (err)
1032 return err;
1033
1034 if (!group->cg_item.ci_name)
1035 group->cg_item.ci_name = group->cg_item.ci_namebuf;
1036
1037 sd = configfs_sb->s_root->d_fsdata;
1038 link_group(to_config_group(sd->s_element), group);
1039
1040 down(&configfs_sb->s_root->d_inode->i_sem);
1041
1042 name.name = group->cg_item.ci_name;
1043 name.len = strlen(name.name);
1044 name.hash = full_name_hash(name.name, name.len);
1045
1046 err = -ENOMEM;
1047 dentry = d_alloc(configfs_sb->s_root, &name);
1048 if (!dentry)
1049 goto out_release;
1050
1051 d_add(dentry, NULL);
1052
1053 err = configfs_attach_group(sd->s_element, &group->cg_item,
1054 dentry);
1055 if (!err)
1056 dentry = NULL;
1057 else
1058 d_delete(dentry);
1059
1060 up(&configfs_sb->s_root->d_inode->i_sem);
1061
1062 if (dentry) {
1063 dput(dentry);
1064out_release:
1065 unlink_group(group);
1066 configfs_release_fs();
1067 }
1068
1069 return err;
1070}
1071
1072void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
1073{
1074 struct config_group *group = &subsys->su_group;
1075 struct dentry *dentry = group->cg_item.ci_dentry;
1076
1077 if (dentry->d_parent != configfs_sb->s_root) {
1078 printk(KERN_ERR "configfs: Tried to unregister non-subsystem!\n");
1079 return;
1080 }
1081
1082 down(&configfs_sb->s_root->d_inode->i_sem);
1083 down(&dentry->d_inode->i_sem);
1084 if (configfs_detach_prep(dentry)) {
1085 printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n");
1086 }
1087 configfs_detach_group(&group->cg_item);
1088 dentry->d_inode->i_flags |= S_DEAD;
1089 up(&dentry->d_inode->i_sem);
1090
1091 d_delete(dentry);
1092
1093 up(&configfs_sb->s_root->d_inode->i_sem);
1094
1095 dput(dentry);
1096
1097 unlink_group(group);
1098 configfs_release_fs();
1099}
1100
1101EXPORT_SYMBOL(configfs_register_subsystem);
1102EXPORT_SYMBOL(configfs_unregister_subsystem);
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
new file mode 100644
index 000000000000..af1ffc9a15c0
--- /dev/null
+++ b/fs/configfs/file.c
@@ -0,0 +1,360 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * file.c - operations for regular (text) files.
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/dnotify.h>
30#include <linux/slab.h>
31#include <asm/uaccess.h>
32#include <asm/semaphore.h>
33
34#include <linux/configfs.h>
35#include "configfs_internal.h"
36
37
38struct configfs_buffer {
39 size_t count;
40 loff_t pos;
41 char * page;
42 struct configfs_item_operations * ops;
43 struct semaphore sem;
44 int needs_read_fill;
45};
46
47
48/**
49 * fill_read_buffer - allocate and fill buffer from item.
50 * @dentry: dentry pointer.
51 * @buffer: data buffer for file.
52 *
53 * Allocate @buffer->page, if it hasn't been already, then call the
54 * config_item's show() method to fill the buffer with this attribute's
55 * data.
56 * This is called only once, on the file's first read.
57 */
58static int fill_read_buffer(struct dentry * dentry, struct configfs_buffer * buffer)
59{
60 struct configfs_attribute * attr = to_attr(dentry);
61 struct config_item * item = to_item(dentry->d_parent);
62 struct configfs_item_operations * ops = buffer->ops;
63 int ret = 0;
64 ssize_t count;
65
66 if (!buffer->page)
67 buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
68 if (!buffer->page)
69 return -ENOMEM;
70
71 count = ops->show_attribute(item,attr,buffer->page);
72 buffer->needs_read_fill = 0;
73 BUG_ON(count > (ssize_t)PAGE_SIZE);
74 if (count >= 0)
75 buffer->count = count;
76 else
77 ret = count;
78 return ret;
79}
80
81
82/**
83 * flush_read_buffer - push buffer to userspace.
84 * @buffer: data buffer for file.
85 * @userbuf: user-passed buffer.
86 * @count: number of bytes requested.
87 * @ppos: file position.
88 *
89 * Copy the buffer we filled in fill_read_buffer() to userspace.
90 * This is done at the reader's leisure, copying and advancing
91 * the amount they specify each time.
92 * This may be called continuously until the buffer is empty.
93 */
94static int flush_read_buffer(struct configfs_buffer * buffer, char __user * buf,
95 size_t count, loff_t * ppos)
96{
97 int error;
98
99 if (*ppos > buffer->count)
100 return 0;
101
102 if (count > (buffer->count - *ppos))
103 count = buffer->count - *ppos;
104
105 error = copy_to_user(buf,buffer->page + *ppos,count);
106 if (!error)
107 *ppos += count;
108 return error ? -EFAULT : count;
109}
110
111/**
112 * configfs_read_file - read an attribute.
113 * @file: file pointer.
114 * @buf: buffer to fill.
115 * @count: number of bytes to read.
116 * @ppos: starting offset in file.
117 *
118 * Userspace wants to read an attribute file. The attribute descriptor
119 * is in the file's ->d_fsdata. The target item is in the directory's
120 * ->d_fsdata.
121 *
122 * We call fill_read_buffer() to allocate and fill the buffer from the
123 * item's show() method exactly once (if the read is happening from
124 * the beginning of the file). That should fill the entire buffer with
125 * all the data the item has to offer for that attribute.
126 * We then call flush_read_buffer() to copy the buffer to userspace
127 * in the increments specified.
128 */
129
130static ssize_t
131configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
132{
133 struct configfs_buffer * buffer = file->private_data;
134 ssize_t retval = 0;
135
136 down(&buffer->sem);
137 if (buffer->needs_read_fill) {
138 if ((retval = fill_read_buffer(file->f_dentry,buffer)))
139 goto out;
140 }
141 pr_debug("%s: count = %d, ppos = %lld, buf = %s\n",
142 __FUNCTION__,count,*ppos,buffer->page);
143 retval = flush_read_buffer(buffer,buf,count,ppos);
144out:
145 up(&buffer->sem);
146 return retval;
147}
148
149
150/**
151 * fill_write_buffer - copy buffer from userspace.
152 * @buffer: data buffer for file.
153 * @userbuf: data from user.
154 * @count: number of bytes in @userbuf.
155 *
156 * Allocate @buffer->page if it hasn't been already, then
157 * copy the user-supplied buffer into it.
158 */
159
160static int
161fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size_t count)
162{
163 int error;
164
165 if (!buffer->page)
166 buffer->page = (char *)get_zeroed_page(GFP_KERNEL);
167 if (!buffer->page)
168 return -ENOMEM;
169
170 if (count > PAGE_SIZE)
171 count = PAGE_SIZE;
172 error = copy_from_user(buffer->page,buf,count);
173 buffer->needs_read_fill = 1;
174 return error ? -EFAULT : count;
175}
176
177
178/**
179 * flush_write_buffer - push buffer to config_item.
180 * @file: file pointer.
181 * @buffer: data buffer for file.
182 *
183 * Get the correct pointers for the config_item and the attribute we're
184 * dealing with, then call the store() method for the attribute,
185 * passing the buffer that we acquired in fill_write_buffer().
186 */
187
188static int
189flush_write_buffer(struct dentry * dentry, struct configfs_buffer * buffer, size_t count)
190{
191 struct configfs_attribute * attr = to_attr(dentry);
192 struct config_item * item = to_item(dentry->d_parent);
193 struct configfs_item_operations * ops = buffer->ops;
194
195 return ops->store_attribute(item,attr,buffer->page,count);
196}
197
198
199/**
200 * configfs_write_file - write an attribute.
201 * @file: file pointer
202 * @buf: data to write
203 * @count: number of bytes
204 * @ppos: starting offset
205 *
206 * Similar to configfs_read_file(), though working in the opposite direction.
207 * We allocate and fill the data from the user in fill_write_buffer(),
208 * then push it to the config_item in flush_write_buffer().
209 * There is no easy way for us to know if userspace is only doing a partial
210 * write, so we don't support them. We expect the entire buffer to come
211 * on the first write.
212 * Hint: if you're writing a value, first read the file, modify only the
213 * the value you're changing, then write entire buffer back.
214 */
215
216static ssize_t
217configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
218{
219 struct configfs_buffer * buffer = file->private_data;
220
221 down(&buffer->sem);
222 count = fill_write_buffer(buffer,buf,count);
223 if (count > 0)
224 count = flush_write_buffer(file->f_dentry,buffer,count);
225 if (count > 0)
226 *ppos += count;
227 up(&buffer->sem);
228 return count;
229}
230
231static int check_perm(struct inode * inode, struct file * file)
232{
233 struct config_item *item = configfs_get_config_item(file->f_dentry->d_parent);
234 struct configfs_attribute * attr = to_attr(file->f_dentry);
235 struct configfs_buffer * buffer;
236 struct configfs_item_operations * ops = NULL;
237 int error = 0;
238
239 if (!item || !attr)
240 goto Einval;
241
242 /* Grab the module reference for this attribute if we have one */
243 if (!try_module_get(attr->ca_owner)) {
244 error = -ENODEV;
245 goto Done;
246 }
247
248 if (item->ci_type)
249 ops = item->ci_type->ct_item_ops;
250 else
251 goto Eaccess;
252
253 /* File needs write support.
254 * The inode's perms must say it's ok,
255 * and we must have a store method.
256 */
257 if (file->f_mode & FMODE_WRITE) {
258
259 if (!(inode->i_mode & S_IWUGO) || !ops->store_attribute)
260 goto Eaccess;
261
262 }
263
264 /* File needs read support.
265 * The inode's perms must say it's ok, and we there
266 * must be a show method for it.
267 */
268 if (file->f_mode & FMODE_READ) {
269 if (!(inode->i_mode & S_IRUGO) || !ops->show_attribute)
270 goto Eaccess;
271 }
272
273 /* No error? Great, allocate a buffer for the file, and store it
274 * it in file->private_data for easy access.
275 */
276 buffer = kmalloc(sizeof(struct configfs_buffer),GFP_KERNEL);
277 if (buffer) {
278 memset(buffer,0,sizeof(struct configfs_buffer));
279 init_MUTEX(&buffer->sem);
280 buffer->needs_read_fill = 1;
281 buffer->ops = ops;
282 file->private_data = buffer;
283 } else
284 error = -ENOMEM;
285 goto Done;
286
287 Einval:
288 error = -EINVAL;
289 goto Done;
290 Eaccess:
291 error = -EACCES;
292 module_put(attr->ca_owner);
293 Done:
294 if (error && item)
295 config_item_put(item);
296 return error;
297}
298
299static int configfs_open_file(struct inode * inode, struct file * filp)
300{
301 return check_perm(inode,filp);
302}
303
304static int configfs_release(struct inode * inode, struct file * filp)
305{
306 struct config_item * item = to_item(filp->f_dentry->d_parent);
307 struct configfs_attribute * attr = to_attr(filp->f_dentry);
308 struct module * owner = attr->ca_owner;
309 struct configfs_buffer * buffer = filp->private_data;
310
311 if (item)
312 config_item_put(item);
313 /* After this point, attr should not be accessed. */
314 module_put(owner);
315
316 if (buffer) {
317 if (buffer->page)
318 free_page((unsigned long)buffer->page);
319 kfree(buffer);
320 }
321 return 0;
322}
323
324struct file_operations configfs_file_operations = {
325 .read = configfs_read_file,
326 .write = configfs_write_file,
327 .llseek = generic_file_llseek,
328 .open = configfs_open_file,
329 .release = configfs_release,
330};
331
332
333int configfs_add_file(struct dentry * dir, const struct configfs_attribute * attr, int type)
334{
335 struct configfs_dirent * parent_sd = dir->d_fsdata;
336 umode_t mode = (attr->ca_mode & S_IALLUGO) | S_IFREG;
337 int error = 0;
338
339 down(&dir->d_inode->i_sem);
340 error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode, type);
341 up(&dir->d_inode->i_sem);
342
343 return error;
344}
345
346
347/**
348 * configfs_create_file - create an attribute file for an item.
349 * @item: item we're creating for.
350 * @attr: atrribute descriptor.
351 */
352
353int configfs_create_file(struct config_item * item, const struct configfs_attribute * attr)
354{
355 BUG_ON(!item || !item->ci_dentry || !attr);
356
357 return configfs_add_file(item->ci_dentry, attr,
358 CONFIGFS_ITEM_ATTR);
359}
360
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
new file mode 100644
index 000000000000..6b274c6d428f
--- /dev/null
+++ b/fs/configfs/inode.c
@@ -0,0 +1,162 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * inode.c - basic inode and dentry operations.
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 * Please see Documentation/filesystems/configfs.txt for more information.
27 */
28
29#undef DEBUG
30
31#include <linux/pagemap.h>
32#include <linux/namei.h>
33#include <linux/backing-dev.h>
34
35#include <linux/configfs.h>
36#include "configfs_internal.h"
37
38extern struct super_block * configfs_sb;
39
40static struct address_space_operations configfs_aops = {
41 .readpage = simple_readpage,
42 .prepare_write = simple_prepare_write,
43 .commit_write = simple_commit_write
44};
45
46static struct backing_dev_info configfs_backing_dev_info = {
47 .ra_pages = 0, /* No readahead */
48 .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
49};
50
51struct inode * configfs_new_inode(mode_t mode)
52{
53 struct inode * inode = new_inode(configfs_sb);
54 if (inode) {
55 inode->i_mode = mode;
56 inode->i_uid = 0;
57 inode->i_gid = 0;
58 inode->i_blksize = PAGE_CACHE_SIZE;
59 inode->i_blocks = 0;
60 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
61 inode->i_mapping->a_ops = &configfs_aops;
62 inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
63 }
64 return inode;
65}
66
67int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *))
68{
69 int error = 0;
70 struct inode * inode = NULL;
71 if (dentry) {
72 if (!dentry->d_inode) {
73 if ((inode = configfs_new_inode(mode))) {
74 if (dentry->d_parent && dentry->d_parent->d_inode) {
75 struct inode *p_inode = dentry->d_parent->d_inode;
76 p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
77 }
78 goto Proceed;
79 }
80 else
81 error = -ENOMEM;
82 } else
83 error = -EEXIST;
84 } else
85 error = -ENOENT;
86 goto Done;
87
88 Proceed:
89 if (init)
90 error = init(inode);
91 if (!error) {
92 d_instantiate(dentry, inode);
93 if (S_ISDIR(mode) || S_ISLNK(mode))
94 dget(dentry); /* pin link and directory dentries in core */
95 } else
96 iput(inode);
97 Done:
98 return error;
99}
100
101/*
102 * Get the name for corresponding element represented by the given configfs_dirent
103 */
104const unsigned char * configfs_get_name(struct configfs_dirent *sd)
105{
106 struct attribute * attr;
107
108 if (!sd || !sd->s_element)
109 BUG();
110
111 /* These always have a dentry, so use that */
112 if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK))
113 return sd->s_dentry->d_name.name;
114
115 if (sd->s_type & CONFIGFS_ITEM_ATTR) {
116 attr = sd->s_element;
117 return attr->name;
118 }
119 return NULL;
120}
121
122
123/*
124 * Unhashes the dentry corresponding to given configfs_dirent
125 * Called with parent inode's i_sem held.
126 */
127void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
128{
129 struct dentry * dentry = sd->s_dentry;
130
131 if (dentry) {
132 spin_lock(&dcache_lock);
133 if (!(d_unhashed(dentry) && dentry->d_inode)) {
134 dget_locked(dentry);
135 __d_drop(dentry);
136 spin_unlock(&dcache_lock);
137 simple_unlink(parent->d_inode, dentry);
138 } else
139 spin_unlock(&dcache_lock);
140 }
141}
142
143void configfs_hash_and_remove(struct dentry * dir, const char * name)
144{
145 struct configfs_dirent * sd;
146 struct configfs_dirent * parent_sd = dir->d_fsdata;
147
148 down(&dir->d_inode->i_sem);
149 list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
150 if (!sd->s_element)
151 continue;
152 if (!strcmp(configfs_get_name(sd), name)) {
153 list_del_init(&sd->s_sibling);
154 configfs_drop_dentry(sd, dir);
155 configfs_put(sd);
156 break;
157 }
158 }
159 up(&dir->d_inode->i_sem);
160}
161
162
diff --git a/fs/configfs/item.c b/fs/configfs/item.c
new file mode 100644
index 000000000000..e07485ac50ad
--- /dev/null
+++ b/fs/configfs/item.c
@@ -0,0 +1,227 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * item.c - library routines for handling generic config items
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 kobject:
22 * kobject is Copyright (c) 2002-2003 Patrick Mochel
23 *
24 * configfs Copyright (C) 2005 Oracle. All rights reserved.
25 *
26 * Please see the file Documentation/filesystems/configfs.txt for
27 * critical information about using the config_item interface.
28 */
29
30#include <linux/string.h>
31#include <linux/module.h>
32#include <linux/stat.h>
33#include <linux/slab.h>
34
35#include <linux/configfs.h>
36
37
38static inline struct config_item * to_item(struct list_head * entry)
39{
40 return container_of(entry,struct config_item,ci_entry);
41}
42
43/* Evil kernel */
44static void config_item_release(struct kref *kref);
45
46/**
47 * config_item_init - initialize item.
48 * @item: item in question.
49 */
50void config_item_init(struct config_item * item)
51{
52 kref_init(&item->ci_kref);
53 INIT_LIST_HEAD(&item->ci_entry);
54}
55
56/**
57 * config_item_set_name - Set the name of an item
58 * @item: item.
59 * @name: name.
60 *
61 * If strlen(name) >= CONFIGFS_ITEM_NAME_LEN, then use a
62 * dynamically allocated string that @item->ci_name points to.
63 * Otherwise, use the static @item->ci_namebuf array.
64 */
65
66int config_item_set_name(struct config_item * item, const char * fmt, ...)
67{
68 int error = 0;
69 int limit = CONFIGFS_ITEM_NAME_LEN;
70 int need;
71 va_list args;
72 char * name;
73
74 /*
75 * First, try the static array
76 */
77 va_start(args,fmt);
78 need = vsnprintf(item->ci_namebuf,limit,fmt,args);
79 va_end(args);
80 if (need < limit)
81 name = item->ci_namebuf;
82 else {
83 /*
84 * Need more space? Allocate it and try again
85 */
86 limit = need + 1;
87 name = kmalloc(limit,GFP_KERNEL);
88 if (!name) {
89 error = -ENOMEM;
90 goto Done;
91 }
92 va_start(args,fmt);
93 need = vsnprintf(name,limit,fmt,args);
94 va_end(args);
95
96 /* Still? Give up. */
97 if (need >= limit) {
98 kfree(name);
99 error = -EFAULT;
100 goto Done;
101 }
102 }
103
104 /* Free the old name, if necessary. */
105 if (item->ci_name && item->ci_name != item->ci_namebuf)
106 kfree(item->ci_name);
107
108 /* Now, set the new name */
109 item->ci_name = name;
110 Done:
111 return error;
112}
113
114EXPORT_SYMBOL(config_item_set_name);
115
116void config_item_init_type_name(struct config_item *item,
117 const char *name,
118 struct config_item_type *type)
119{
120 config_item_set_name(item, name);
121 item->ci_type = type;
122 config_item_init(item);
123}
124EXPORT_SYMBOL(config_item_init_type_name);
125
126void config_group_init_type_name(struct config_group *group, const char *name,
127 struct config_item_type *type)
128{
129 config_item_set_name(&group->cg_item, name);
130 group->cg_item.ci_type = type;
131 config_group_init(group);
132}
133EXPORT_SYMBOL(config_group_init_type_name);
134
135struct config_item * config_item_get(struct config_item * item)
136{
137 if (item)
138 kref_get(&item->ci_kref);
139 return item;
140}
141
142/**
143 * config_item_cleanup - free config_item resources.
144 * @item: item.
145 */
146
147void config_item_cleanup(struct config_item * item)
148{
149 struct config_item_type * t = item->ci_type;
150 struct config_group * s = item->ci_group;
151 struct config_item * parent = item->ci_parent;
152
153 pr_debug("config_item %s: cleaning up\n",config_item_name(item));
154 if (item->ci_name != item->ci_namebuf)
155 kfree(item->ci_name);
156 item->ci_name = NULL;
157 if (t && t->ct_item_ops && t->ct_item_ops->release)
158 t->ct_item_ops->release(item);
159 if (s)
160 config_group_put(s);
161 if (parent)
162 config_item_put(parent);
163}
164
165static void config_item_release(struct kref *kref)
166{
167 config_item_cleanup(container_of(kref, struct config_item, ci_kref));
168}
169
170/**
171 * config_item_put - decrement refcount for item.
172 * @item: item.
173 *
174 * Decrement the refcount, and if 0, call config_item_cleanup().
175 */
176void config_item_put(struct config_item * item)
177{
178 if (item)
179 kref_put(&item->ci_kref, config_item_release);
180}
181
182
183/**
184 * config_group_init - initialize a group for use
185 * @k: group
186 */
187
188void config_group_init(struct config_group *group)
189{
190 config_item_init(&group->cg_item);
191 INIT_LIST_HEAD(&group->cg_children);
192}
193
194
195/**
196 * config_group_find_obj - search for item in group.
197 * @group: group we're looking in.
198 * @name: item's name.
199 *
200 * Lock group via @group->cg_subsys, and iterate over @group->cg_list,
201 * looking for a matching config_item. If matching item is found
202 * take a reference and return the item.
203 */
204
205struct config_item * config_group_find_obj(struct config_group * group, const char * name)
206{
207 struct list_head * entry;
208 struct config_item * ret = NULL;
209
210 /* XXX LOCKING! */
211 list_for_each(entry,&group->cg_children) {
212 struct config_item * item = to_item(entry);
213 if (config_item_name(item) &&
214 !strcmp(config_item_name(item), name)) {
215 ret = config_item_get(item);
216 break;
217 }
218 }
219 return ret;
220}
221
222
223EXPORT_SYMBOL(config_item_init);
224EXPORT_SYMBOL(config_group_init);
225EXPORT_SYMBOL(config_item_get);
226EXPORT_SYMBOL(config_item_put);
227
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
new file mode 100644
index 000000000000..1a2f6f6a4d91
--- /dev/null
+++ b/fs/configfs/mount.c
@@ -0,0 +1,159 @@
1/* -*- mode: c; c-basic-offset: 8; -*-
2 * vim: noexpandtab sw=8 ts=8 sts=0:
3 *
4 * mount.c - operations for initializing and mounting configfs.
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/mount.h>
30#include <linux/pagemap.h>
31#include <linux/init.h>
32
33#include <linux/configfs.h>
34#include "configfs_internal.h"
35
36/* Random magic number */
37#define CONFIGFS_MAGIC 0x62656570
38
39struct vfsmount * configfs_mount = NULL;
40struct super_block * configfs_sb = NULL;
41static int configfs_mnt_count = 0;
42
43static struct super_operations configfs_ops = {
44 .statfs = simple_statfs,
45 .drop_inode = generic_delete_inode,
46};
47
48static struct config_group configfs_root_group = {
49 .cg_item = {
50 .ci_namebuf = "root",
51 .ci_name = configfs_root_group.cg_item.ci_namebuf,
52 },
53};
54
55int configfs_is_root(struct config_item *item)
56{
57 return item == &configfs_root_group.cg_item;
58}
59
60static struct configfs_dirent configfs_root = {
61 .s_sibling = LIST_HEAD_INIT(configfs_root.s_sibling),
62 .s_children = LIST_HEAD_INIT(configfs_root.s_children),
63 .s_element = &configfs_root_group.cg_item,
64 .s_type = CONFIGFS_ROOT,
65};
66
67static int configfs_fill_super(struct super_block *sb, void *data, int silent)
68{
69 struct inode *inode;
70 struct dentry *root;
71
72 sb->s_blocksize = PAGE_CACHE_SIZE;
73 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
74 sb->s_magic = CONFIGFS_MAGIC;
75 sb->s_op = &configfs_ops;
76 configfs_sb = sb;
77
78 inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
79 if (inode) {
80 inode->i_op = &configfs_dir_inode_operations;
81 inode->i_fop = &configfs_dir_operations;
82 /* directory inodes start off with i_nlink == 2 (for "." entry) */
83 inode->i_nlink++;
84 } else {
85 pr_debug("configfs: could not get root inode\n");
86 return -ENOMEM;
87 }
88
89 root = d_alloc_root(inode);
90 if (!root) {
91 pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
92 iput(inode);
93 return -ENOMEM;
94 }
95 config_group_init(&configfs_root_group);
96 configfs_root_group.cg_item.ci_dentry = root;
97 root->d_fsdata = &configfs_root;
98 sb->s_root = root;
99 return 0;
100}
101
102static struct super_block *configfs_get_sb(struct file_system_type *fs_type,
103 int flags, const char *dev_name, void *data)
104{
105 return get_sb_single(fs_type, flags, data, configfs_fill_super);
106}
107
108static struct file_system_type configfs_fs_type = {
109 .owner = THIS_MODULE,
110 .name = "configfs",
111 .get_sb = configfs_get_sb,
112 .kill_sb = kill_litter_super,
113};
114
115int configfs_pin_fs(void)
116{
117 return simple_pin_fs("configfs", &configfs_mount,
118 &configfs_mnt_count);
119}
120
121void configfs_release_fs(void)
122{
123 simple_release_fs(&configfs_mount, &configfs_mnt_count);
124}
125
126
127static decl_subsys(config, NULL, NULL);
128
129static int __init configfs_init(void)
130{
131 int err;
132
133 kset_set_kset_s(&config_subsys, kernel_subsys);
134 err = subsystem_register(&config_subsys);
135 if (err)
136 return err;
137
138 err = register_filesystem(&configfs_fs_type);
139 if (err) {
140 printk(KERN_ERR "configfs: Unable to register filesystem!\n");
141 subsystem_unregister(&config_subsys);
142 }
143
144 return err;
145}
146
147static void __exit configfs_exit(void)
148{
149 unregister_filesystem(&configfs_fs_type);
150 subsystem_unregister(&config_subsys);
151}
152
153MODULE_AUTHOR("Oracle");
154MODULE_LICENSE("GPL");
155MODULE_VERSION("0.0.1");
156MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
157
158module_init(configfs_init);
159module_exit(configfs_exit);
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
new file mode 100644
index 000000000000..50f5840521a9
--- /dev/null
+++ b/fs/configfs/symlink.c
@@ -0,0 +1,281 @@
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
31#include <linux/configfs.h>
32#include "configfs_internal.h"
33
34static int item_depth(struct config_item * item)
35{
36 struct config_item * p = item;
37 int depth = 0;
38 do { depth++; } while ((p = p->ci_parent) && !configfs_is_root(p));
39 return depth;
40}
41
42static int item_path_length(struct config_item * item)
43{
44 struct config_item * p = item;
45 int length = 1;
46 do {
47 length += strlen(config_item_name(p)) + 1;
48 p = p->ci_parent;
49 } while (p && !configfs_is_root(p));
50 return length;
51}
52
53static void fill_item_path(struct config_item * item, char * buffer, int length)
54{
55 struct config_item * p;
56
57 --length;
58 for (p = item; p && !configfs_is_root(p); p = p->ci_parent) {
59 int cur = strlen(config_item_name(p));
60
61 /* back up enough to print this bus id with '/' */
62 length -= cur;
63 strncpy(buffer + length,config_item_name(p),cur);
64 *(buffer + --length) = '/';
65 }
66}
67
68static int create_link(struct config_item *parent_item,
69 struct config_item *item,
70 struct dentry *dentry)
71{
72 struct configfs_dirent *target_sd = item->ci_dentry->d_fsdata;
73 struct configfs_symlink *sl;
74 int ret;
75
76 ret = -ENOMEM;
77 sl = kmalloc(sizeof(struct configfs_symlink), GFP_KERNEL);
78 if (sl) {
79 sl->sl_target = config_item_get(item);
80 /* FIXME: needs a lock, I'd bet */
81 list_add(&sl->sl_list, &target_sd->s_links);
82 ret = configfs_create_link(sl, parent_item->ci_dentry,
83 dentry);
84 if (ret) {
85 list_del_init(&sl->sl_list);
86 config_item_put(item);
87 kfree(sl);
88 }
89 }
90
91 return ret;
92}
93
94
95static int get_target(const char *symname, struct nameidata *nd,
96 struct config_item **target)
97{
98 int ret;
99
100 ret = path_lookup(symname, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, nd);
101 if (!ret) {
102 if (nd->dentry->d_sb == configfs_sb) {
103 *target = configfs_get_config_item(nd->dentry);
104 if (!*target) {
105 ret = -ENOENT;
106 path_release(nd);
107 }
108 } else
109 ret = -EPERM;
110 }
111
112 return ret;
113}
114
115
116int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
117{
118 int ret;
119 struct nameidata nd;
120 struct config_item *parent_item;
121 struct config_item *target_item;
122 struct config_item_type *type;
123
124 ret = -EPERM; /* What lack-of-symlink returns */
125 if (dentry->d_parent == configfs_sb->s_root)
126 goto out;
127
128 parent_item = configfs_get_config_item(dentry->d_parent);
129 type = parent_item->ci_type;
130
131 if (!type || !type->ct_item_ops ||
132 !type->ct_item_ops->allow_link)
133 goto out_put;
134
135 ret = get_target(symname, &nd, &target_item);
136 if (ret)
137 goto out_put;
138
139 ret = type->ct_item_ops->allow_link(parent_item, target_item);
140 if (!ret)
141 ret = create_link(parent_item, target_item, dentry);
142
143 config_item_put(target_item);
144 path_release(&nd);
145
146out_put:
147 config_item_put(parent_item);
148
149out:
150 return ret;
151}
152
153int configfs_unlink(struct inode *dir, struct dentry *dentry)
154{
155 struct configfs_dirent *sd = dentry->d_fsdata;
156 struct configfs_symlink *sl;
157 struct config_item *parent_item;
158 struct config_item_type *type;
159 int ret;
160
161 ret = -EPERM; /* What lack-of-symlink returns */
162 if (!(sd->s_type & CONFIGFS_ITEM_LINK))
163 goto out;
164
165 if (dentry->d_parent == configfs_sb->s_root)
166 BUG();
167
168 sl = sd->s_element;
169
170 parent_item = configfs_get_config_item(dentry->d_parent);
171 type = parent_item->ci_type;
172
173 list_del_init(&sd->s_sibling);
174 configfs_drop_dentry(sd, dentry->d_parent);
175 dput(dentry);
176 configfs_put(sd);
177
178 /*
179 * drop_link() must be called before
180 * list_del_init(&sl->sl_list), so that the order of
181 * drop_link(this, target) and drop_item(target) is preserved.
182 */
183 if (type && type->ct_item_ops &&
184 type->ct_item_ops->drop_link)
185 type->ct_item_ops->drop_link(parent_item,
186 sl->sl_target);
187
188 /* FIXME: Needs lock */
189 list_del_init(&sl->sl_list);
190
191 /* Put reference from create_link() */
192 config_item_put(sl->sl_target);
193 kfree(sl);
194
195 config_item_put(parent_item);
196
197 ret = 0;
198
199out:
200 return ret;
201}
202
203static int configfs_get_target_path(struct config_item * item, struct config_item * target,
204 char *path)
205{
206 char * s;
207 int depth, size;
208
209 depth = item_depth(item);
210 size = item_path_length(target) + depth * 3 - 1;
211 if (size > PATH_MAX)
212 return -ENAMETOOLONG;
213
214 pr_debug("%s: depth = %d, size = %d\n", __FUNCTION__, depth, size);
215
216 for (s = path; depth--; s += 3)
217 strcpy(s,"../");
218
219 fill_item_path(target, path, size);
220 pr_debug("%s: path = '%s'\n", __FUNCTION__, path);
221
222 return 0;
223}
224
225static int configfs_getlink(struct dentry *dentry, char * path)
226{
227 struct config_item *item, *target_item;
228 int error = 0;
229
230 item = configfs_get_config_item(dentry->d_parent);
231 if (!item)
232 return -EINVAL;
233
234 target_item = configfs_get_config_item(dentry);
235 if (!target_item) {
236 config_item_put(item);
237 return -EINVAL;
238 }
239
240 down_read(&configfs_rename_sem);
241 error = configfs_get_target_path(item, target_item, path);
242 up_read(&configfs_rename_sem);
243
244 config_item_put(item);
245 config_item_put(target_item);
246 return error;
247
248}
249
250static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
251{
252 int error = -ENOMEM;
253 unsigned long page = get_zeroed_page(GFP_KERNEL);
254
255 if (page) {
256 error = configfs_getlink(dentry, (char *)page);
257 if (!error) {
258 nd_set_link(nd, (char *)page);
259 return (void *)page;
260 }
261 }
262
263 nd_set_link(nd, ERR_PTR(error));
264 return NULL;
265}
266
267static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
268 void *cookie)
269{
270 if (cookie) {
271 unsigned long page = (unsigned long)cookie;
272 free_page(page);
273 }
274}
275
276struct inode_operations configfs_symlink_inode_operations = {
277 .follow_link = configfs_follow_link,
278 .readlink = generic_readlink,
279 .put_link = configfs_put_link,
280};
281