一、开篇
本文所有代码出自linux内核版本:4.1.15
在start_kernel函数中将调用proc_root_init()
初始化proc文件系统的目录。该函数定义如下(/fs/proc/root.c):
void __init proc_root_init(void)
{
int err;
proc_init_inodecache();
err = register_filesystem(&proc_fs_type);
if (err)
return;
proc_self_init();
proc_thread_self_init();
proc_symlink("mounts", NULL, "self/mounts");
proc_net_init();
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
proc_mkdir("fs", NULL);
proc_mkdir("driver", NULL);
proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
proc_create_mount_point("openprom");
#endif
proc_tty_init();
proc_mkdir("bus", NULL);
proc_sys_init();
}
在proc_root_init()
函数开始处,调用proc_init_inodecache()
函数分配proc的inode缓存(proc_inode_cachep
),如下代码片段(/fs/proc/inode.c):
void __init proc_init_inodecache(void)
{
proc_inode_cachep = kmem_cache_create("proc_inode_cache",
sizeof(struct proc_inode),
0, (SLAB_RECLAIM_ACCOUNT|
SLAB_MEM_SPREAD|SLAB_PANIC),
init_once);
}
上述代码中,proc_inode_cachep
是一个指向struct kmem_cache
结构的指针。当对proc文件系统分配inode时,将在proc_inode_cachep指向的slab缓存区域中分配内存,这个操作由proc_alloc_inode()
函数完成,如下代码:
static struct inode *proc_alloc_inode(struct super_block *sb)
{
/* 省略了部分代码 */
ei = (struct proc_inode *)kmem_cache_alloc(proc_inode_cachep, GFP_KERNEL);
/* 省略了部分代码 */
return inode;
}
当释放proc文件系统分配的inode时,将调用proc_i_callback()
函数释放proc_inode_cachep指向的slab缓存区(proc_i_callback()
函数被proc_destroy_inode()
调用),如下代码所示:
static void proc_i_callback(struct rcu_head *head)
{
struct inode *inode = container_of(head, struct inode, i_rcu);
kmem_cache_free(proc_inode_cachep, PROC_I(inode));
}
对于proc文件系统来说,对proc_inode_cachep指向的slab缓存区域的分配和释放两个操作函数都被注册到了proc文件系统超级块的操作集合(proc_sops
)中,如下代码所示(/fs/proc/inode.c):
static const struct super_operations proc_sops = {
/* 分配inode */
.alloc_inode = proc_alloc_inode,
/* 释放inode */
.destroy_inode = proc_destroy_inode,
/* ......*/
};
回到proc_root_init()
函数中,会继续调用register_filesystem()
向linux内核注册proc文件系统,其文件系统的类型描述定义如下:
static struct file_system_type proc_fs_type = {
.name = "proc",
.mount = proc_mount,
.kill_sb = proc_kill_sb,
.fs_flags = FS_USERNS_VISIBLE | FS_USERNS_MOUNT,
};
在向内核中注册了proc文件系统后,会调用proc_self_init()
函数(fs/proc/self.c)为self分配索引节点号(/proc/self目录指:访问/proc文件系统的进程)。
接着,将调用proc_setup_thread_self()
函数,该函数将设置/proc/thread-self目录,其中包含有关当前线程的信息。如下代码片段:
proc_self_init();
proc_thread_self_init();
紧接着,会创建/proc/self/mounts,它将包含调用的挂载点:
proc_symlink("mounts", NULL, "self/mounts");
接着会创建/proc/fs、/proc/driver、/proc/mounts、/proc/net、/proc/sys、/proc/tty相关proc文件系统的信息条目,如下代码:
proc_net_init();
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
proc_mkdir("fs", NULL);
proc_mkdir("driver", NULL);
proc_create_mount_point("fs/nfsd"); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
proc_create_mount_point("openprom");
#endif
proc_tty_init();
proc_mkdir("bus", NULL);
在proc_root_init()
函数的最后,会调用proc_sys_init()
函数创建/proc/sys目录并初始化sysctl。
二、结尾
至此,proc_root_init()
函数就分析完毕啦。总结一下,该函数主要用于为proc文件系统创建目录
我们可以使用proc_mkdir()
函数创建自己的proc文件系统目录,例如小生这里创建了一个目录如下:
proc_mkdir("iriczhao", NULL);
编译linux内核后运行,在bash shell中输入ls /proc/
,命令将显示我们自己定义的目录,如下图所示:
(当然,以上操作似乎无任何意义,这么做,无非加深对linux内核的理解啦。毕竟动手实践,永远是把控linux内核的最佳方式!)
linux内核如何向proc文件系统递交内核本身的信息,这又是另外的话题了…
搜索/关注【嵌入式小生】wx公众号,获取更多精彩内容>>>>