Linux Kernel /proc 虚拟文件系统源码分析

该文章正在更新中……

Linux Kernel 里的 /proc 目录是一个虚拟文件系统,里面存放的是反应当前 Linux Kernel 运行状态的一系列特殊文件。之所以称之为是特殊文件,是因为这些文件其实不具有「实体」,当使用 cat 等指令尝试读取这些文件里的内容的时候,Linux Kernel 会调用特殊的函数,统计相关信息,然后以字节流的方式返回。对于读取该文件的程序(例如 cat)来说,这些虚拟文件和普通的文件并无差别,这也是 Linux 「一切皆文件」的一种体现。

proc 文件内容的输出是通过一个内核 API seq_file 实现的,这个 API 用于在内核之间传递信息,同时也能让内核对输出的信息进行格式化。更详细的关于 seq_file 的内容可以参考这篇文章。具体来说,对于每一个 /proc 下的文件来说,需要单独实现 seq_open() 函数接口,在该函数内统计需要的信息,然后按照格式顺序使用 seq_printf() 进行输出。

这个文件里存放的是当前操作系统所安装的文件系统的信息。示例:

/linuxkernel-proc/image-1.png

其中每一行代表一个已安装的文件系统。总共有六列,从左到右分别是:

  1. 设备名:这是挂载的文件系统所在的设备或伪文件系统的名称。对于硬盘分区,这可能是类似于 /dev/sda1 的设备文件名。对于网络文件系统,可能是一个URL,如 server:/path

  2. 挂载点:这是文件系统挂载到的目录路径。

  3. 文件系统类型:这是文件系统的类型,如 ext4xfsnfstmpfs 等。

  4. 挂载选项:这是挂载时使用的选项,以逗号分隔。它们定义了文件系统的各种挂载参数,如 ro 表示只读,rw 表示读写,noexec 禁止执行二进制文件,nosuid 禁止set-user-identifierset-group-identifier权限等。

  5. 转储频率(dump frequency):这是用于dump程序的备份操作的。在大多数现代系统中,这个值通常是0,表示不备份。

  6. 检查顺序(pass number):在启动时,fsck 程序使用这个字段来确定检查文件系统的顺序。根文件系统应该是1,其他文件系统应该是2或更大。如果为0,则表示不检查。

需要注意的是,第五、六列的这两个信息在现代操作系统中已经没有作用了,这里保留下来是为了和久标准保持兼容,所以可以看到全都是 0。

这些信息是通过遍历内核中的已打开文件系统的链表获取的,直接找到对应的信息输出即可。挂载点则需要进行递归输出。

这个文件列出了系统中所有已注册的设备及其主设备号。设备通常分为两类:

  1. 字符设备(Character devices):这些设备通常是以字符为单位进行数据传输的,例如终端(terminals)、打印机(printers)或其他类型的串行端口。它们通常不支持随机访问数据。

  2. 块设备(Block devices):这些设备是以数据块为单位进行数据传输的,例如硬盘、光盘驱动器或其他支持随机访问的存储设备。

/proc/devices 文件中的内容通常分为两个部分:

  • 第一部分列出了字符设备,包括设备的主设备号和设备类型名称。
  • 第二部分列出了块设备,同样包括设备的主设备号和设备类型名称。

这个文件的格式如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Character devices:
  1 mem
  4 /dev/vc/0
  4 tty
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  ...

Block devices:
  7 loop
  8 sd
  9 md
 11 sr
  ...

在上面的例子中:

  • 对于字符设备部分,1/dev/mem 设备的主设备号,它代表内存访问设备。
  • 对于块设备部分,8 是 SCSI 磁盘设备(通常是硬盘)的主设备号,sd 表示 SCSI 磁盘设备。

主设备号是内核用来识别处理该设备文件请求的驱动程序的标识符。当用户程序执行设备操作时(如读取或写入设备文件),主设备号用于确定哪个驱动程序应该处理这些请求。

与该模块相关的代码位于 fs/proc/devices.cfs/char_dev.cblock/genhd.c 里。

fs/char_dev.c 中的 chrdev_show() 函数提供了获取字节设备信息的功能。其具体实现方式就是遍历字节设备表,然后直接输出。而 block/genhd.c 中的 blkdev_show() 则是提供了获取块设备信息的功能,实现方式相同。fs/proc/devices.c 中的 devinfo_show() 则只需要调用这两个函数,就可以实现输出设备信息的功能。