179 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * mount.c - operations for initializing and mounting configfs.4 *5 * Based on sysfs:6 * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel7 *8 * configfs Copyright (C) 2005 Oracle. All rights reserved.9 */10 11#include <linux/fs.h>12#include <linux/module.h>13#include <linux/mount.h>14#include <linux/fs_context.h>15#include <linux/pagemap.h>16#include <linux/init.h>17#include <linux/slab.h>18 19#include <linux/configfs.h>20#include "configfs_internal.h"21 22/* Random magic number */23#define CONFIGFS_MAGIC 0x6265657024 25static struct vfsmount *configfs_mount = NULL;26struct kmem_cache *configfs_dir_cachep;27static int configfs_mnt_count = 0;28 29 30static void configfs_free_inode(struct inode *inode)31{32 if (S_ISLNK(inode->i_mode))33 kfree(inode->i_link);34 free_inode_nonrcu(inode);35}36 37static const struct super_operations configfs_ops = {38 .statfs = simple_statfs,39 .drop_inode = generic_delete_inode,40 .free_inode = configfs_free_inode,41};42 43static struct config_group configfs_root_group = {44 .cg_item = {45 .ci_namebuf = "root",46 .ci_name = configfs_root_group.cg_item.ci_namebuf,47 },48};49 50int configfs_is_root(struct config_item *item)51{52 return item == &configfs_root_group.cg_item;53}54 55static struct configfs_dirent configfs_root = {56 .s_sibling = LIST_HEAD_INIT(configfs_root.s_sibling),57 .s_children = LIST_HEAD_INIT(configfs_root.s_children),58 .s_element = &configfs_root_group.cg_item,59 .s_type = CONFIGFS_ROOT,60 .s_iattr = NULL,61};62 63static int configfs_fill_super(struct super_block *sb, struct fs_context *fc)64{65 struct inode *inode;66 struct dentry *root;67 68 sb->s_blocksize = PAGE_SIZE;69 sb->s_blocksize_bits = PAGE_SHIFT;70 sb->s_magic = CONFIGFS_MAGIC;71 sb->s_op = &configfs_ops;72 sb->s_time_gran = 1;73 74 inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,75 &configfs_root, sb);76 if (inode) {77 inode->i_op = &configfs_root_inode_operations;78 inode->i_fop = &configfs_dir_operations;79 /* directory inodes start off with i_nlink == 2 (for "." entry) */80 inc_nlink(inode);81 } else {82 pr_debug("could not get root inode\n");83 return -ENOMEM;84 }85 86 root = d_make_root(inode);87 if (!root) {88 pr_debug("%s: could not get root dentry!\n",__func__);89 return -ENOMEM;90 }91 config_group_init(&configfs_root_group);92 configfs_root_group.cg_item.ci_dentry = root;93 root->d_fsdata = &configfs_root;94 sb->s_root = root;95 sb->s_d_op = &configfs_dentry_ops; /* the rest get that */96 return 0;97}98 99static int configfs_get_tree(struct fs_context *fc)100{101 return get_tree_single(fc, configfs_fill_super);102}103 104static const struct fs_context_operations configfs_context_ops = {105 .get_tree = configfs_get_tree,106};107 108static int configfs_init_fs_context(struct fs_context *fc)109{110 fc->ops = &configfs_context_ops;111 return 0;112}113 114static struct file_system_type configfs_fs_type = {115 .owner = THIS_MODULE,116 .name = "configfs",117 .init_fs_context = configfs_init_fs_context,118 .kill_sb = kill_litter_super,119};120MODULE_ALIAS_FS("configfs");121 122struct dentry *configfs_pin_fs(void)123{124 int err = simple_pin_fs(&configfs_fs_type, &configfs_mount,125 &configfs_mnt_count);126 return err ? ERR_PTR(err) : configfs_mount->mnt_root;127}128 129void configfs_release_fs(void)130{131 simple_release_fs(&configfs_mount, &configfs_mnt_count);132}133 134 135static int __init configfs_init(void)136{137 int err = -ENOMEM;138 139 configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",140 sizeof(struct configfs_dirent),141 0, 0, NULL);142 if (!configfs_dir_cachep)143 goto out;144 145 err = sysfs_create_mount_point(kernel_kobj, "config");146 if (err)147 goto out2;148 149 err = register_filesystem(&configfs_fs_type);150 if (err)151 goto out3;152 153 return 0;154out3:155 pr_err("Unable to register filesystem!\n");156 sysfs_remove_mount_point(kernel_kobj, "config");157out2:158 kmem_cache_destroy(configfs_dir_cachep);159 configfs_dir_cachep = NULL;160out:161 return err;162}163 164static void __exit configfs_exit(void)165{166 unregister_filesystem(&configfs_fs_type);167 sysfs_remove_mount_point(kernel_kobj, "config");168 kmem_cache_destroy(configfs_dir_cachep);169 configfs_dir_cachep = NULL;170}171 172MODULE_AUTHOR("Oracle");173MODULE_LICENSE("GPL");174MODULE_VERSION("0.0.2");175MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");176 177core_initcall(configfs_init);178module_exit(configfs_exit);179