您的位置:首页 > 其它

内核proc文件系统与seq接口(3)---内核proc文件底层结构浅析

2013-10-25 16:30 423 查看
前面讲了proc文件系统的编程,其实在使用API的时候注意一下proc文件系统的实现也是很有益处的。在学习使用proc的时候我顺便看了一下proc的底层实现,发现原理非常简单,毕竟是一个基于内存的文件系统。
首先众所周知,所有的文件系统都位于VFS的层,proc也不例外。在内核启动的时,start_kernel在完成了VFS的初始化不久就调用了:

#ifdef CONFIG_PROC_FS

proc_root_init();

#endif

用于初始化proc文件系统:

fs/proc/root.c

void __init proc_root_init(void)

{

struct vfsmount *mnt;

int err;

proc_init_inodecache();

err = register_filesystem(&proc_fs_type);
//向VFS注册procfs

if (err)

return;

mnt = kern_mount_data(&proc_fs_type, &init_pid_ns);

if (IS_ERR(mnt)) {

unregister_filesystem(&proc_fs_type);

return;

}

init_pid_ns.proc_mnt = mnt;

proc_symlink("mounts", NULL, "self/mounts");
//创建“mounts”符号连接文件

proc_net_init();
//创建“net”符号连接及内部目录树结构

#ifdef CONFIG_SYSVIPC

proc_mkdir("sysvipc", NULL);
//创建“sysvipc”目录

#endif

proc_mkdir("fs", NULL);
//创建“fs”目录

proc_mkdir("driver", NULL);
//创建“driver”目录

proc_mkdir("fs/nfsd", NULL); /* somewhere for the
nfsd filesystem to be mounted */

#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)

/* just give it a mountpoint */

proc_mkdir("openprom", NULL);

#endif

proc_tty_init();
//创建“tty”目录及内部结构

#ifdef CONFIG_PROC_DEVICETREE

proc_device_tree_init();

#endif

proc_mkdir("bus", NULL);
//创建“bus”目录

proc_sys_init();
//创建“sys”目录并初始化

}

在这之后,许多内核组件和模块就可以向proc文件系统及其子目录添加目录和文件了。其中最重要的数据结构体就是:struct proc_dir_entry,她在《内核proc文件系统与seq接口(2)---内核proc文件系统编程接口》介绍过。她相当于proc文件系统中的数据节点,procfs中许多文件、符号连接和目录文件都是由她表示的。但是请注意,并不是左右的proc文件都对应这样的数据结构,对于/proc/sys、/proc/${PID}/等特定目录下的文件时需要时动态生成的,有其自己的内部实现。而这个proc_dir_entry只对普通的proc文件实现,及我们自己创建的proc文件。

其根目录的表示:
fs/proc/root.c

/*

* This is the root "inode" in the /proc
tree..

*/

struct proc_dir_entry proc_root = {

.low_ino = PROC_ROOT_INO,

.namelen = 5,

.name = "/proc",

.mode = S_IFDIR | S_IRUGO | S_IXUGO,

.nlink = 2,

.count = ATOMIC_INIT(1),

.proc_iops = &proc_root_inode_operations,

.proc_fops = &proc_root_operations,

.parent = &proc_root,

};

除了这个节点的结构体在代码中静态定义的之外,其他所有的节点都是系统和模块初始化产生的。也除了这个节点的mane字符串是在内核映像的只读数据段中,其他的节点的name字符串都是在创建的时候紧跟在其struct proc_dir_entry之后的,如下图:




而看了源码(fs/proc/generic.c)你就会很快的了解这个文件系统的数据连接方式:用*next指针通过单向链表连接同目录下文件;用*parent指针指向父目录的proc_dir_entry结构体;用*subdir指针指向本目录中的文件(如果这个文件目录的话),总体底层结构示意图如下所示:

上图只是一个结构示意图,一些指针的指向不确定的,比如proc_root的*subdir肯定不是指向sys,因为初始化之后还有很多目录和文件要产生。但是/root目录下单向链表的最后一个应该是mounts,因为他是最早注册的(起码在3.0上是这样)。上图同时示意了符号连接注册后的一般情况。

对于一个目录注册后的一般如下,主要是注意*proc_iops inode操作函数和*proc_fops 文件操作函数的注册:




《内核proc文件系统与seq接口(2)---内核proc文件系统编程接口》中曾经介绍过,对于创建
/proc 入口,有两种选择:
(1)使用proc的默认操作函数集proc_file_operations,但必须实现回调函数*read_proc和*write_proc,示意图如下:




(2)使用自己实现的file_operations,以下用/proc/config.gz文件的实现做示意:



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
以上的解析只是对procfs的浅析,有兴趣的朋友可以自己看看fs/proc/generic.c,非常简单的文件系统实现,是一个很好的学习样本。RTFSC – Read The Fucking Source Code。
原文转载自:http://blog.chinaunix.net/uid-28253945-id-3382864.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: