0333cd8a3f
Since sysfs no longer stores fs directory information in the dcache on a permanent basis kill_litter_super it is inappropriate and actively wrong. It will decrement the count on all dentries left in the dcache before trying to free them. At the moment this is not biting us only because we never unmount sysfs. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Tejun Heo <htejun@gmail.com> Cc: Cornelia Huck <cornelia.huck@de.ibm.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
106 lines
2.3 KiB
C
106 lines
2.3 KiB
C
/*
|
|
* mount.c - operations for initializing and mounting sysfs.
|
|
*/
|
|
|
|
#define DEBUG
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/mount.h>
|
|
#include <linux/pagemap.h>
|
|
#include <linux/init.h>
|
|
|
|
#include "sysfs.h"
|
|
|
|
/* Random magic number */
|
|
#define SYSFS_MAGIC 0x62656572
|
|
|
|
struct vfsmount *sysfs_mount;
|
|
struct super_block * sysfs_sb = NULL;
|
|
struct kmem_cache *sysfs_dir_cachep;
|
|
|
|
static const struct super_operations sysfs_ops = {
|
|
.statfs = simple_statfs,
|
|
.drop_inode = generic_delete_inode,
|
|
};
|
|
|
|
struct sysfs_dirent sysfs_root = {
|
|
.s_count = ATOMIC_INIT(1),
|
|
.s_flags = SYSFS_ROOT,
|
|
.s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
|
.s_ino = 1,
|
|
};
|
|
|
|
static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
|
|
{
|
|
struct inode *inode;
|
|
struct dentry *root;
|
|
|
|
sb->s_blocksize = PAGE_CACHE_SIZE;
|
|
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
|
|
sb->s_magic = SYSFS_MAGIC;
|
|
sb->s_op = &sysfs_ops;
|
|
sb->s_time_gran = 1;
|
|
sysfs_sb = sb;
|
|
|
|
/* get root inode, initialize and unlock it */
|
|
inode = sysfs_get_inode(&sysfs_root);
|
|
if (!inode) {
|
|
pr_debug("sysfs: could not get root inode\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
/* instantiate and link root dentry */
|
|
root = d_alloc_root(inode);
|
|
if (!root) {
|
|
pr_debug("%s: could not get root dentry!\n",__FUNCTION__);
|
|
iput(inode);
|
|
return -ENOMEM;
|
|
}
|
|
sysfs_root.s_dentry = root;
|
|
root->d_fsdata = &sysfs_root;
|
|
sb->s_root = root;
|
|
return 0;
|
|
}
|
|
|
|
static int sysfs_get_sb(struct file_system_type *fs_type,
|
|
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
|
|
{
|
|
return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
|
|
}
|
|
|
|
static struct file_system_type sysfs_fs_type = {
|
|
.name = "sysfs",
|
|
.get_sb = sysfs_get_sb,
|
|
.kill_sb = kill_anon_super,
|
|
};
|
|
|
|
int __init sysfs_init(void)
|
|
{
|
|
int err = -ENOMEM;
|
|
|
|
sysfs_dir_cachep = kmem_cache_create("sysfs_dir_cache",
|
|
sizeof(struct sysfs_dirent),
|
|
0, 0, NULL);
|
|
if (!sysfs_dir_cachep)
|
|
goto out;
|
|
|
|
err = register_filesystem(&sysfs_fs_type);
|
|
if (!err) {
|
|
sysfs_mount = kern_mount(&sysfs_fs_type);
|
|
if (IS_ERR(sysfs_mount)) {
|
|
printk(KERN_ERR "sysfs: could not mount!\n");
|
|
err = PTR_ERR(sysfs_mount);
|
|
sysfs_mount = NULL;
|
|
unregister_filesystem(&sysfs_fs_type);
|
|
goto out_err;
|
|
}
|
|
} else
|
|
goto out_err;
|
|
out:
|
|
return err;
|
|
out_err:
|
|
kmem_cache_destroy(sysfs_dir_cachep);
|
|
sysfs_dir_cachep = NULL;
|
|
goto out;
|
|
}
|