aboutsummaryrefslogtreecommitdiffstats
path: root/fs/configfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/configfs')
-rw-r--r--fs/configfs/Kconfig4
-rw-r--r--fs/configfs/configfs_internal.h5
-rw-r--r--fs/configfs/dir.c63
-rw-r--r--fs/configfs/inode.c9
-rw-r--r--fs/configfs/mount.c9
5 files changed, 55 insertions, 35 deletions
diff --git a/fs/configfs/Kconfig b/fs/configfs/Kconfig
index 13587cc97a0b..9febcdefdfdc 100644
--- a/fs/configfs/Kconfig
+++ b/fs/configfs/Kconfig
@@ -1,8 +1,8 @@
1config CONFIGFS_FS 1config CONFIGFS_FS
2 tristate "Userspace-driven configuration filesystem" 2 tristate "Userspace-driven configuration filesystem"
3 depends on SYSFS 3 select SYSFS
4 help 4 help
5 configfs is a ram-based filesystem that provides the converse 5 configfs is a RAM-based filesystem that provides the converse
6 of sysfs's functionality. Where sysfs is a filesystem-based 6 of sysfs's functionality. Where sysfs is a filesystem-based
7 view of kernel objects, configfs is a filesystem-based manager 7 view of kernel objects, configfs is a filesystem-based manager
8 of kernel objects, or config_items. 8 of kernel objects, or config_items.
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index da6061a6df40..82bda8fdfc1c 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -90,6 +90,7 @@ extern const struct file_operations configfs_file_operations;
90extern const struct file_operations bin_fops; 90extern const struct file_operations bin_fops;
91extern const struct inode_operations configfs_dir_inode_operations; 91extern const struct inode_operations configfs_dir_inode_operations;
92extern const struct inode_operations configfs_symlink_inode_operations; 92extern const struct inode_operations configfs_symlink_inode_operations;
93extern const struct dentry_operations configfs_dentry_ops;
93 94
94extern int configfs_symlink(struct inode *dir, struct dentry *dentry, 95extern int configfs_symlink(struct inode *dir, struct dentry *dentry,
95 const char *symname); 96 const char *symname);
@@ -120,7 +121,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
120{ 121{
121 struct config_item * item = NULL; 122 struct config_item * item = NULL;
122 123
123 spin_lock(&dcache_lock); 124 spin_lock(&dentry->d_lock);
124 if (!d_unhashed(dentry)) { 125 if (!d_unhashed(dentry)) {
125 struct configfs_dirent * sd = dentry->d_fsdata; 126 struct configfs_dirent * sd = dentry->d_fsdata;
126 if (sd->s_type & CONFIGFS_ITEM_LINK) { 127 if (sd->s_type & CONFIGFS_ITEM_LINK) {
@@ -129,7 +130,7 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
129 } else 130 } else
130 item = config_item_get(sd->s_element); 131 item = config_item_get(sd->s_element);
131 } 132 }
132 spin_unlock(&dcache_lock); 133 spin_unlock(&dentry->d_lock);
133 134
134 return item; 135 return item;
135} 136}
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 0b502f80c691..9a37a9b6de3a 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -53,11 +53,14 @@ DEFINE_SPINLOCK(configfs_dirent_lock);
53static void configfs_d_iput(struct dentry * dentry, 53static void configfs_d_iput(struct dentry * dentry,
54 struct inode * inode) 54 struct inode * inode)
55{ 55{
56 struct configfs_dirent * sd = dentry->d_fsdata; 56 struct configfs_dirent *sd = dentry->d_fsdata;
57 57
58 if (sd) { 58 if (sd) {
59 BUG_ON(sd->s_dentry != dentry); 59 BUG_ON(sd->s_dentry != dentry);
60 /* Coordinate with configfs_readdir */
61 spin_lock(&configfs_dirent_lock);
60 sd->s_dentry = NULL; 62 sd->s_dentry = NULL;
63 spin_unlock(&configfs_dirent_lock);
61 configfs_put(sd); 64 configfs_put(sd);
62 } 65 }
63 iput(inode); 66 iput(inode);
@@ -67,12 +70,12 @@ static void configfs_d_iput(struct dentry * dentry,
67 * We _must_ delete our dentries on last dput, as the chain-to-parent 70 * We _must_ delete our dentries on last dput, as the chain-to-parent
68 * behavior is required to clear the parents of default_groups. 71 * behavior is required to clear the parents of default_groups.
69 */ 72 */
70static int configfs_d_delete(struct dentry *dentry) 73static int configfs_d_delete(const struct dentry *dentry)
71{ 74{
72 return 1; 75 return 1;
73} 76}
74 77
75static const struct dentry_operations configfs_dentry_ops = { 78const struct dentry_operations configfs_dentry_ops = {
76 .d_iput = configfs_d_iput, 79 .d_iput = configfs_d_iput,
77 /* simple_delete_dentry() isn't exported */ 80 /* simple_delete_dentry() isn't exported */
78 .d_delete = configfs_d_delete, 81 .d_delete = configfs_d_delete,
@@ -232,10 +235,8 @@ int configfs_make_dirent(struct configfs_dirent * parent_sd,
232 235
233 sd->s_mode = mode; 236 sd->s_mode = mode;
234 sd->s_dentry = dentry; 237 sd->s_dentry = dentry;
235 if (dentry) { 238 if (dentry)
236 dentry->d_fsdata = configfs_get(sd); 239 dentry->d_fsdata = configfs_get(sd);
237 dentry->d_op = &configfs_dentry_ops;
238 }
239 240
240 return 0; 241 return 0;
241} 242}
@@ -278,7 +279,6 @@ static int create_dir(struct config_item * k, struct dentry * p,
278 error = configfs_create(d, mode, init_dir); 279 error = configfs_create(d, mode, init_dir);
279 if (!error) { 280 if (!error) {
280 inc_nlink(p->d_inode); 281 inc_nlink(p->d_inode);
281 (d)->d_op = &configfs_dentry_ops;
282 } else { 282 } else {
283 struct configfs_dirent *sd = d->d_fsdata; 283 struct configfs_dirent *sd = d->d_fsdata;
284 if (sd) { 284 if (sd) {
@@ -371,9 +371,7 @@ int configfs_create_link(struct configfs_symlink *sl,
371 CONFIGFS_ITEM_LINK); 371 CONFIGFS_ITEM_LINK);
372 if (!err) { 372 if (!err) {
373 err = configfs_create(dentry, mode, init_symlink); 373 err = configfs_create(dentry, mode, init_symlink);
374 if (!err) 374 if (err) {
375 dentry->d_op = &configfs_dentry_ops;
376 else {
377 struct configfs_dirent *sd = dentry->d_fsdata; 375 struct configfs_dirent *sd = dentry->d_fsdata;
378 if (sd) { 376 if (sd) {
379 spin_lock(&configfs_dirent_lock); 377 spin_lock(&configfs_dirent_lock);
@@ -399,8 +397,7 @@ static void remove_dir(struct dentry * d)
399 if (d->d_inode) 397 if (d->d_inode)
400 simple_rmdir(parent->d_inode,d); 398 simple_rmdir(parent->d_inode,d);
401 399
402 pr_debug(" o %s removing done (%d)\n",d->d_name.name, 400 pr_debug(" o %s removing done (%d)\n",d->d_name.name, d->d_count);
403 atomic_read(&d->d_count));
404 401
405 dput(parent); 402 dput(parent);
406} 403}
@@ -448,7 +445,6 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
448 return error; 445 return error;
449 } 446 }
450 447
451 dentry->d_op = &configfs_dentry_ops;
452 d_rehash(dentry); 448 d_rehash(dentry);
453 449
454 return 0; 450 return 0;
@@ -493,7 +489,10 @@ static struct dentry * configfs_lookup(struct inode *dir,
493 * If it doesn't exist and it isn't a NOT_PINNED item, 489 * If it doesn't exist and it isn't a NOT_PINNED item,
494 * it must be negative. 490 * it must be negative.
495 */ 491 */
496 return simple_lookup(dir, dentry, nd); 492 if (dentry->d_name.len > NAME_MAX)
493 return ERR_PTR(-ENAMETOOLONG);
494 d_add(dentry, NULL);
495 return NULL;
497 } 496 }
498 497
499out: 498out:
@@ -693,7 +692,8 @@ static int create_default_group(struct config_group *parent_group,
693 sd = child->d_fsdata; 692 sd = child->d_fsdata;
694 sd->s_type |= CONFIGFS_USET_DEFAULT; 693 sd->s_type |= CONFIGFS_USET_DEFAULT;
695 } else { 694 } else {
696 d_delete(child); 695 BUG_ON(child->d_inode);
696 d_drop(child);
697 dput(child); 697 dput(child);
698 } 698 }
699 } 699 }
@@ -994,7 +994,7 @@ static int configfs_dump(struct configfs_dirent *sd, int level)
994 * This describes these functions and their helpers. 994 * This describes these functions and their helpers.
995 * 995 *
996 * Allow another kernel system to depend on a config_item. If this 996 * Allow another kernel system to depend on a config_item. If this
997 * happens, the item cannot go away until the dependant can live without 997 * happens, the item cannot go away until the dependent can live without
998 * it. The idea is to give client modules as simple an interface as 998 * it. The idea is to give client modules as simple an interface as
999 * possible. When a system asks them to depend on an item, they just 999 * possible. When a system asks them to depend on an item, they just
1000 * call configfs_depend_item(). If the item is live and the client 1000 * call configfs_depend_item(). If the item is live and the client
@@ -1549,7 +1549,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
1549 struct configfs_dirent * parent_sd = dentry->d_fsdata; 1549 struct configfs_dirent * parent_sd = dentry->d_fsdata;
1550 struct configfs_dirent *cursor = filp->private_data; 1550 struct configfs_dirent *cursor = filp->private_data;
1551 struct list_head *p, *q = &cursor->s_sibling; 1551 struct list_head *p, *q = &cursor->s_sibling;
1552 ino_t ino; 1552 ino_t ino = 0;
1553 int i = filp->f_pos; 1553 int i = filp->f_pos;
1554 1554
1555 switch (i) { 1555 switch (i) {
@@ -1577,6 +1577,7 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
1577 struct configfs_dirent *next; 1577 struct configfs_dirent *next;
1578 const char * name; 1578 const char * name;
1579 int len; 1579 int len;
1580 struct inode *inode = NULL;
1580 1581
1581 next = list_entry(p, struct configfs_dirent, 1582 next = list_entry(p, struct configfs_dirent,
1582 s_sibling); 1583 s_sibling);
@@ -1585,9 +1586,28 @@ static int configfs_readdir(struct file * filp, void * dirent, filldir_t filldir
1585 1586
1586 name = configfs_get_name(next); 1587 name = configfs_get_name(next);
1587 len = strlen(name); 1588 len = strlen(name);
1588 if (next->s_dentry) 1589
1589 ino = next->s_dentry->d_inode->i_ino; 1590 /*
1590 else 1591 * We'll have a dentry and an inode for
1592 * PINNED items and for open attribute
1593 * files. We lock here to prevent a race
1594 * with configfs_d_iput() clearing
1595 * s_dentry before calling iput().
1596 *
1597 * Why do we go to the trouble? If
1598 * someone has an attribute file open,
1599 * the inode number should match until
1600 * they close it. Beyond that, we don't
1601 * care.
1602 */
1603 spin_lock(&configfs_dirent_lock);
1604 dentry = next->s_dentry;
1605 if (dentry)
1606 inode = dentry->d_inode;
1607 if (inode)
1608 ino = inode->i_ino;
1609 spin_unlock(&configfs_dirent_lock);
1610 if (!inode)
1591 ino = iunique(configfs_sb, 2); 1611 ino = iunique(configfs_sb, 2);
1592 1612
1593 if (filldir(dirent, name, len, filp->f_pos, ino, 1613 if (filldir(dirent, name, len, filp->f_pos, ino,
@@ -1687,7 +1707,8 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
1687 err = configfs_attach_group(sd->s_element, &group->cg_item, 1707 err = configfs_attach_group(sd->s_element, &group->cg_item,
1688 dentry); 1708 dentry);
1689 if (err) { 1709 if (err) {
1690 d_delete(dentry); 1710 BUG_ON(dentry->d_inode);
1711 d_drop(dentry);
1691 dput(dentry); 1712 dput(dentry);
1692 } else { 1713 } else {
1693 spin_lock(&configfs_dirent_lock); 1714 spin_lock(&configfs_dirent_lock);
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index cf78d44a8d6a..c83f4768eeaa 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -135,6 +135,7 @@ struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
135{ 135{
136 struct inode * inode = new_inode(configfs_sb); 136 struct inode * inode = new_inode(configfs_sb);
137 if (inode) { 137 if (inode) {
138 inode->i_ino = get_next_ino();
138 inode->i_mapping->a_ops = &configfs_aops; 139 inode->i_mapping->a_ops = &configfs_aops;
139 inode->i_mapping->backing_dev_info = &configfs_backing_dev_info; 140 inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
140 inode->i_op = &configfs_inode_operations; 141 inode->i_op = &configfs_inode_operations;
@@ -249,18 +250,14 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
249 struct dentry * dentry = sd->s_dentry; 250 struct dentry * dentry = sd->s_dentry;
250 251
251 if (dentry) { 252 if (dentry) {
252 spin_lock(&dcache_lock);
253 spin_lock(&dentry->d_lock); 253 spin_lock(&dentry->d_lock);
254 if (!(d_unhashed(dentry) && dentry->d_inode)) { 254 if (!(d_unhashed(dentry) && dentry->d_inode)) {
255 dget_locked(dentry); 255 dget_dlock(dentry);
256 __d_drop(dentry); 256 __d_drop(dentry);
257 spin_unlock(&dentry->d_lock); 257 spin_unlock(&dentry->d_lock);
258 spin_unlock(&dcache_lock);
259 simple_unlink(parent->d_inode, dentry); 258 simple_unlink(parent->d_inode, dentry);
260 } else { 259 } else
261 spin_unlock(&dentry->d_lock); 260 spin_unlock(&dentry->d_lock);
262 spin_unlock(&dcache_lock);
263 }
264 } 261 }
265} 262}
266 263
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 8c8d64230c2d..ecc62178beda 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -101,19 +101,20 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
101 configfs_root_group.cg_item.ci_dentry = root; 101 configfs_root_group.cg_item.ci_dentry = root;
102 root->d_fsdata = &configfs_root; 102 root->d_fsdata = &configfs_root;
103 sb->s_root = root; 103 sb->s_root = root;
104 sb->s_d_op = &configfs_dentry_ops; /* the rest get that */
104 return 0; 105 return 0;
105} 106}
106 107
107static int configfs_get_sb(struct file_system_type *fs_type, 108static struct dentry *configfs_do_mount(struct file_system_type *fs_type,
108 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 109 int flags, const char *dev_name, void *data)
109{ 110{
110 return get_sb_single(fs_type, flags, data, configfs_fill_super, mnt); 111 return mount_single(fs_type, flags, data, configfs_fill_super);
111} 112}
112 113
113static struct file_system_type configfs_fs_type = { 114static struct file_system_type configfs_fs_type = {
114 .owner = THIS_MODULE, 115 .owner = THIS_MODULE,
115 .name = "configfs", 116 .name = "configfs",
116 .get_sb = configfs_get_sb, 117 .mount = configfs_do_mount,
117 .kill_sb = kill_litter_super, 118 .kill_sb = kill_litter_super,
118}; 119};
119 120