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

 前面讲了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。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值