sys文件系统的创建和初始化过程

在kernal start函数中,创建sys文件系统的函数调用栈:

start_kernel

        >vfs_caches_init

                >mnt_init

                       >kernfs_init

                       >sysfs_init

当前分析位置:kernfs_init   

start_kernel

        >vfs_caches_init

                >mnt_init

                       >kernfs_init     <====当前分析位置

                       >sysfs_init

//为全局变量struct kmem_cache *kernfs_node_cache申请内存空间并初始化部分成员值
void __init kernfs_init(void)
{

	/*
	 * the slab is freed in RCU context, so kernfs_find_and_get_node_by_ino
	 * can access the slab lock free. This could introduce stale nodes,
	 * please see how kernfs_find_and_get_node_by_ino filters out stale
	 * nodes.
	 */
	kernfs_node_cache = kmem_cache_create("kernfs_node_cache",
					      sizeof(struct kernfs_node),
					      0,
					      SLAB_PANIC | SLAB_TYPESAFE_BY_RCU,
					      NULL);
}

struct kmem_cache *
kmem_cache_create(const char *name, size_t size, size_t offset,
	unsigned long flags, void (*ctor)(void *))
{
	struct kmem_cache *ret = malloc(sizeof(*ret));

	pthread_mutex_init(&ret->lock, NULL);
	ret->size = size;
	ret->nr_objs = 0;
	ret->objs = NULL;
	ret->ctor = ctor;
	return ret;
}

当前分析位置:sysfs_init 

start_kernel

        >vfs_caches_init

                >mnt_init

                       >kernfs_init 

                       >sysfs_init    <====当前分析位置

相关数据结构:
/*
通过kernfs_root创建的基数树并维护目录kernfs_node与id的关联,
可以通过树查找到id对应的kernfs_node,而目录kernfs_node之间的
层级父子关系则通过kernfs_node中的rb和dir维护
*/
struct kernfs_root {
	/* published fields */
	struct kernfs_node	*kn;//树的第一个节点?
	unsigned int		flags;	/* KERNFS_ROOT_* flags */

	/* private fields, do not use outside kernfs proper */
	struct idr		ino_idr;//关键成员,基数树,维护目录kernfs_node与id的关联
	u32			next_generation;//基数树已申请的节点总数,也是下一代将新添加的节点的序号
	struct kernfs_syscall_ops *syscall_ops;//文件系统相关的操作函数集

	/* list of kernfs_super_info of this root, protected by kernfs_mutex */
	struct list_head	supers;

	wait_queue_head_t	deactivate_waitq;
};
/*
 * kernfs_node - the building block of kernfs hierarchy.  Each and every
 * kernfs node is represented by single kernfs_node.  Most fields are
 * private to kernfs and shouldn't be accessed directly by kernfs users.
 *
 * As long as s_count reference is held, the kernfs_node itself is
 * accessible.  Dereferencing elem or any other outer entity requires
 * active reference.
 */
struct kernfs_node {
	atomic_t		count;
	atomic_t		active;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
	struct lockdep_map	dep_map;
#endif
	/*
	 * Use kernfs_get_parent() and kernfs_name/path() instead of
	 * accessing the following two fields directly.  If the node is
	 * never moved to a different parent, it is safe to access the
	 * parent directly.
	 */
	struct kernfs_node	*parent;//关键
	const char		*name;

	struct rb_node		rb;//被挂接在其父节点的所有子节点所挂载的红黑树中

	const void		*ns;	/* namespace tag */
	unsigned int		hash;	/* ns + name hash */ //关键
	union {
		struct kernfs_elem_dir		dir;//关键
		struct kernfs_elem_symlink	symlink;
		struct kernfs_elem_attr		attr;
	};

	void			*priv;//关键

	union kernfs_node_id	id;//关键
	unsigned short		flags;
	umode_t			mode;
	struct kernfs_iattrs	*iattr;
};

struct kernfs_elem_dir {
	unsigned long		subdirs;
	/* children rbtree starts here and goes through kn->rb */
	struct rb_root		children;//指向本节点的所有子节点所挂载的红黑树的根节点的kernfs_node.rb 

	/*
	 * The kernfs hierarchy this directory belongs to.  This fits
	 * better directly in kernfs_node but is here to save space.
	 */
	struct kernfs_root	*root;
};

static struct kernfs_root *sysfs_root;//代表sys文件系统的根
struct kernfs_node *sysfs_root_kn;//代表sys文件系统的根的节点

int __init sysfs_init(void)
{
	int err;
	//创建sys系统根
	sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
					NULL); <=======当前分析位置
	if (IS_ERR(sysfs_root))
		return PTR_ERR(sysfs_root);
	//sys系统根的目录
	sysfs_root_kn = sysfs_root->kn;
	将待注册的文件系统添加到已注册的文件系统列表中
	err = register_filesystem(&sysfs_fs_type);
	if (err) {
		kernfs_destroy_root(sysfs_root);
		return err;
	}

	return 0;
}

sysfs_init
    >kernfs_create_root <=======当前分析位置

struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
				       unsigned int flags, void *priv)
{
	struct kernfs_root *root;
	struct kernfs_node *kn;

	root = kzalloc(sizeof(*root), GFP_KERNEL);
	if (!root)
		return ERR_PTR(-ENOMEM);

	idr_init(&root->ino_idr);
	INIT_LIST_HEAD(&root->supers);
	root->next_generation = 1;

	kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
			       KERNFS_DIR); <=======当前分析位置
	if (!kn) {
		idr_destroy(&root->ino_idr);
		kfree(root);
		return ERR_PTR(-ENOMEM);
	}

	kn->priv = priv;//此时为空
	kn->dir.root = root;//记录创建的kn所属的根

	root->syscall_ops = scops;//添加相应的回调函数
	root->flags = flags;
	root->kn = kn;//第一个创建的kn是树根对应的kn目录
	init_waitqueue_head(&root->deactivate_waitq);

	if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
		kernfs_activate(kn);

	return root;
}

sysfs_init
    >kernfs_create_root
        >__kernfs_new_node <=======当前分析位置

//在根文件系统上创建并添加目录kernfs_node
static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
					     const char *name, umode_t mode,
					     unsigned flags)
{
	struct kernfs_node *kn;
	u32 gen;
	int cursor;
	int ret;

	name = kstrdup_const(name, GFP_KERNEL);
	if (!name)
		return NULL;

	kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL);
	if (!kn)
		goto err_out1;

	idr_preload(GFP_KERNEL);
	spin_lock(&kernfs_idr_lock);
	//获取下一个申请的id
	cursor = idr_get_cursor(&root->ino_idr);
	//在基数树上申请id,并将kn绑定到id对应的树节点上,便于通过id查找kn
	ret = idr_alloc_cyclic(&root->ino_idr, kn, 1, 0, GFP_ATOMIC);
	//root->next_generation++记录当前节点是树中添加的第几个节点
	if (ret >= 0 && ret < cursor)
		root->next_generation++;
	gen = root->next_generation;
	spin_unlock(&kernfs_idr_lock);
	idr_preload_end();
	if (ret < 0)
		goto err_out2;
    //将id信息记录到kn中
	kn->id.ino = ret;
	kn->id.generation = gen;

	/*
	 * set ino first. This barrier is paired with atomic_inc_not_zero in
	 * kernfs_find_and_get_node_by_ino
	 */
	smp_mb__before_atomic();
	atomic_set(&kn->count, 1);
	atomic_set(&kn->active, KN_DEACTIVATED_BIAS);
	RB_CLEAR_NODE(&kn->rb);

	kn->name = name;
	kn->mode = mode;
	kn->flags = flags;

	return kn;

 err_out2:
	kmem_cache_free(kernfs_node_cache, kn);
 err_out1:
	kfree_const(name);
	return NULL;
}

返回kernfs_create_root
sysfs_init
    >kernfs_create_root <=======当前分析位置

struct kernfs_root *kernfs_create_root(struct kernfs_syscall_ops *scops,
				       unsigned int flags, void *priv)
{
	struct kernfs_root *root;
	struct kernfs_node *kn;

	root = kzalloc(sizeof(*root), GFP_KERNEL);
	if (!root)
		return ERR_PTR(-ENOMEM);

	idr_init(&root->ino_idr);
	INIT_LIST_HEAD(&root->supers);
	root->next_generation = 1;

	kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
			       KERNFS_DIR);
	if (!kn) {
		idr_destroy(&root->ino_idr);
		kfree(root);
		return ERR_PTR(-ENOMEM);
	}
 <=======当前分析位置
	kn->priv = priv;//此时为空
	kn->dir.root = root;//记录创建的kn所属的根

	root->syscall_ops = scops;//添加相应的回调函数
	root->flags = flags;
	root->kn = kn;//第一个创建的kn是树根对应的kn目录
	init_waitqueue_head(&root->deactivate_waitq);

	if (!(root->flags & KERNFS_ROOT_CREATE_DEACTIVATED))
		kernfs_activate(kn);

	return root;
}

返回sysfs_init
sysfs_init <=======当前分析位置

int __init sysfs_init(void)
{
	int err;
	//创建sys系统根
	sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
					NULL);
	if (IS_ERR(sysfs_root))
		return PTR_ERR(sysfs_root);
	//sys系统根的目录
	sysfs_root_kn = sysfs_root->kn;
	将待注册的文件系统添加到已注册的文件系统列表中
	err = register_filesystem(&sysfs_fs_type); <=======当前分析位置
	if (err) {
		kernfs_destroy_root(sysfs_root);
		return err;
	}

	return 0;
}

sysfs_init
    >kernfs_create_root
    >register_filesystem <=======当前分析位置

//将待注册的文件系统添加到已注册的文件系统列表中,直到文件系统被注销时才是空闲
int register_filesystem(struct file_system_type * fs)
{
	int res = 0;
	struct file_system_type ** p;

	BUG_ON(strchr(fs->name, '.'));
	if (fs->next)
		return -EBUSY;//根据本函数最终的注册效果是将带注册系统添加到已注册列表可知,这里表示该注册的系统已经被注册
	write_lock(&file_systems_lock);
	//由于已注册链表最后一个元素的next为空,所以这里需要再查询一下
	p = find_filesystem(fs->name, strlen(fs->name));
	if (*p)
		res = -EBUSY;该注册的系统已经被注册
	else
		*p = fs;
	write_unlock(&file_systems_lock);
	return res;
}

返回sysfs_init
sysfs_init <=======当前分析位置

int __init sysfs_init(void)
{
	int err;
	//创建sys系统根
	sysfs_root = kernfs_create_root(NULL, KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK,
					NULL);
	if (IS_ERR(sysfs_root))
		return PTR_ERR(sysfs_root);
	//sys系统根的目录
	sysfs_root_kn = sysfs_root->kn;
	将待注册的文件系统添加到已注册的文件系统列表中
	err = register_filesystem(&sysfs_fs_type);
	if (err) {
		kernfs_destroy_root(sysfs_root);
		return err;
	}

	return 0;
}

总结:

1、 为全局变量struct kmem_cache *kernfs_node_cache申请内存空间并初始化部分成员值。

2、创建sys文件系统根struct kernfs_root *sysfs_root,包含文件系统根的信息,并为sysfs_root添加一个kernfs_node *sysfs_root_kn代表sys文件系统的根的节点。

3、将待注册的文件系统sysfs_fs_type 添加到已注册的文件系统列表struct file_system_type *file_systems中。

static struct file_system_type sysfs_fs_type = {
    .name        = "sysfs",
    .mount        = sysfs_mount,
    .kill_sb    = sysfs_kill_sb,
    .fs_flags    = FS_USERNS_MOUNT,
}

你可能感兴趣的:(linux,开发语言,linux,c语言)