当我写时会发生什么cat /proc/cpuinfo
。这是操作系统的命名管道(或其他东西),它会动态读取 CPU 信息并在每次调用它时生成该文本?
答案1
每当您读取 下的文件时/proc
,都会调用内核中的一些代码来计算要读取的文本作为文件内容。内容是动态生成的这一事实解释了为什么几乎所有文件的时间都报告为现在,大小报告为 0 — 此处您应该将 0 读作“不知道”。与通常的文件系统不同,挂载在 上的文件系统/proc
称为进程文件系统,不会从磁盘或其他存储介质(如 FAT、ext2、zfs 等)或通过网络(如 NFS、Samba 等)加载数据,并且不会调用用户代码(与保险丝)。
Procfs 存在于大多数非 BSD unice 中。它诞生于 AT&T 贝尔实验室UNIX 第 8 版作为报告有关进程的信息的一种方式(并且ps
通常是用于读取信息的漂亮打印机/proc
)。大多数 procfs 实现都有一个文件或目录,用于/proc/123
报告有关 PID 123 的进程的信息。Linux 使用更多报告系统状态的条目(包括您的示例 )扩展了 proc 文件系统/proc/cpuinfo
。
过去,Linux/proc
获取了提供有关驱动程序信息的各种文件,但现在不推荐使用这种用途,而是使用/sys
,/proc
现在发展缓慢。为了向后兼容,类似/proc/bus
和 的条目保留在原来的位置,但更新的类似接口是在 下创建的。在这个答案中,我将重点关注 Linux。/proc/fs/ext4
/sys
有关 Linux 的文档的第一个和第二个入口点/proc
是:
当文档未涵盖时,您的第三个入口点是阅读源码。您可以在您的计算机上下载源代码,但这是一个巨大的程序,并且LXRLinux 交叉引用是一个很大的帮助。 (LXR 有很多变体;lxr.linux.no
目前运行的版本是最好的,但不幸的是该网站经常宕机。)需要一点 C 知识,但您不需要成为一名程序员来追踪神秘的值。
条目的核心处理/proc
是在fs/proc
目录。任何驱动程序都可以在 中注册条目/proc
(尽管如上所述,现在已不推荐使用/sys
),因此,如果您在 中找不到所需的内容fs/proc
,请在其他地方查找。驱动程序调用声明的函数include/linux/proc_fs.h
。内核版本最高可达 3.9提供函数create_proc_entry
和一些包装器(尤其是create_proc_read_entry
)和内核版本3.10及以上仅提供proc_create
和proc_create_data
(以及更多)。
举/proc/cpuinfo
个例子,搜索"cpuinfo"
会引导您调用proc_create("cpuinfo, …")
infs/proc/cpuinfo.c
。您可以看到该代码几乎是样板代码:由于大多数文件/proc
只是转储一些文本数据,因此有辅助函数可以执行此操作。仅有一个seq_operations
结构,真正的肉在cpuinfo_op
数据结构,与体系结构相关,通常定义在arch/<architecture>/kernel/setup.c
(有时是不同的文件)中。以 x86 为例,我们得到arch/x86/kernel/cpu/proc.c
。其中主要功能是show_cpuinfo
打印出想要的文件内容;基础设施的其余部分按照读取过程请求的速度将数据提供给读取过程。您可以看到从内核中各个变量中的数据动态组装的数据,包括一些动态计算的数字,例如CPU频率。
其中很大一部分/proc
是 中的每个进程信息/proc/<PID>
。这些条目注册于fs/proc/base.c
, 在里面tgid_base_stuff
大批;此处注册的一些函数是在其他文件中定义的。让我们看一些如何生成这些条目的示例:
cmdline
是由生成的proc_pid_cmdline
在同一个文件中。它在流程中定位数据并将其打印出来。clear_refs
与我们迄今为止看到的条目不同,它是可写但不可读取的。因此proc_clear_refs_operations
结构体定义了一个clear_refs_write
有功能但没有读取功能。cwd
是一个符号链接(有点神奇),由proc_cwd_link
, 哪个查找进程的当前目录并将其作为链接内容返回。fd
是一个子目录。对目录本身的操作定义在proc_fd_operations
数据结构(除了枚举条目的函数之外,它们都是样板文件,proc_readfd
,它枚举进程的打开文件),而对条目的操作位于`proc_fd_inode_操作。
的另一个重要领域/proc
是/proc/sys
,它是一个直接接口sysctl
。从此层次结构中的条目读取会返回相应 sysctl 值的值,写入会设置 sysctl 值。 sysctl 的入口点位于fs/proc/proc_sysctl.c
。 Sysctl 有自己的注册系统register_sysctl
和朋友。
答案2
当你试图深入了解幕后正在发生什么样的魔法时,你最好的朋友就是你strace
。学习操作这个工具是你能做的最好的事情之一,以便更好地了解幕后发生的疯狂魔法。
$ strace -s 200 -m strace.log cat /proc/cpuinfo
...
read(3, "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 37\nmodel name\t: Intel(R) Core(TM) i5 CPU M 560 @ 2.67GHz\nstepping\t: 5\nmicrocode\t: 0x4\ncpu MHz\t\t: 1199.000\ncache size\t: 3072 KB\nphy"..., 65536) = 3464
write(1, "processor\t: 0\nvendor_id\t: GenuineIntel\ncpu family\t: 6\nmodel\t\t: 37\nmodel name\t: Intel(R) Core(TM) i5 CPU M 560 @ 2.67GHz\nstepping\t: 5\nmicrocode\t: 0x4\ncpu MHz\t\t: 1199.000\ncache size\t: 3072 KB\nphy"..., 3464) = 3464
read(3, "", 65536) = 0
close(3) = 0
...
从上面的输出中,您可以看到这/proc/cpuinfo
只是一个常规文件,或者至少看起来是一个。那么让我们深入挖掘一下。
更深层次的潜水
#1- 与 ls..查看文件本身,它似乎“只是一个文件”。
$ ls -l /proc/cpuinfo
-r--r--r--. 1 root root 0 Mar 26 22:45 /proc/cpuinfo
但仔细看看。我们得到的第一个提示是它的特殊性,请注意文件的大小是 0 字节。
#2- 与统计..如果我们现在使用查看该文件,stat
我们可以得到下一个提示,即/proc/cpuinfo
.
$ stat /proc/cpuinfo
File: ‘/proc/cpuinfo’
Size: 0 Blocks: 0 IO Block: 1024 regular empty file
Device: 3h/3dInode: 4026532023 Links: 1
Access: (0444/-r--r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: system_u:object_r:proc_t:s0
Access: 2014-03-26 22:46:18.390753719 -0400
Modify: 2014-03-26 22:46:18.390753719 -0400
Change: 2014-03-26 22:46:18.390753719 -0400
Birth: -
运行#2
$ stat /proc/cpuinfo
File: ‘/proc/cpuinfo’
Size: 0 Blocks: 0 IO Block: 1024 regular empty file
Device: 3h/3dInode: 4026532023 Links: 1
Access: (0444/-r--r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Context: system_u:object_r:proc_t:s0
Access: 2014-03-26 22:46:19.945753704 -0400
Modify: 2014-03-26 22:46:19.945753704 -0400
Change: 2014-03-26 22:46:19.945753704 -0400
Birth: -
注意到访问、修改和更改时间了吗?每次访问它们都会发生变化。这三个因素都会发生这样的变化,这是非常不寻常的。除非进行编辑,否则文件的时间戳属性通常保持不变。
#3- 带文件..还有另一个线索表明该文件绝不是常规文件:
$ file /proc/cpuinfo
/proc/cpuinfo: empty
如果它是命名管道的某种表现形式,它将显示类似于以下文件之一:
$ ls -l /dev/initctl /dev/zero
prw-------. 1 root root 0 Mar 26 20:09 /dev/initctl
crw-rw-rw-. 1 root root 1, 5 Mar 27 00:39 /dev/zero
$ file /dev/initctl /dev/zero
/dev/initctl: fifo (named pipe)
/dev/zero: character special
如果我们触摸emptyfile
,/proc/cpuinfo
确实看起来更像是一个文件,而不是一个管道:
$ touch emptyfile
$ ls -l emptyfile
-rw-rw-r--. 1 saml saml 0 Mar 27 07:40 emptyfile
$ file emptyfile
emptyfile: empty
#4- 与安装..
所以在这一点上我们需要退后一步并缩小一点。我们正在查看一个特定的文件,但也许我们应该查看该文件所在的文件系统。为此,我们可以使用该mount
命令。
$ mount | grep " /proc "
proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)
好的,所以文件系统类型是 类型proc
。不同的文件系统类型也是如此/proc
,这是我们暗示下面的文件/proc
是特殊的。它们不仅仅是您常用的文件。因此,让我们了解有关proc
文件系统特殊之处的更多信息。
看一下mount
的手册页:
proc 文件系统不与特殊设备关联,并且在安装它时,可以使用任意关键字(例如 proc)来代替设备规范。 (习惯选择 none 不太幸运:来自 umount 的错误消息“none busy”可能会令人困惑。)
如果我们看一下proc
的手册页:
proc 文件系统是一个伪文件系统,用作内核数据结构的接口。它通常安装在/proc。其中大部分是只读的,但有些文件允许更改内核变量。
在同一个手册页中再往下一点:
/proc/cpu信息
这是 CPU 和系统架构相关项的集合,对于每个支持的架构都有不同的列表。两个常见的条目是处理器,它提供 CPU 编号和 bogomips;在内核初始化期间计算的系统常量。 SMP 机器具有每个 CPU 的信息。 lscpu(1) 命令从此文件中收集其信息。
手册页的底部是对内核文档的引用,您可以在此处找到该文档,标题为:/proc 文件系统。引用该文件:
proc 文件系统充当内核中内部数据结构的接口。它可用于获取有关系统的信息并在运行时更改某些内核参数(sysctl)。
结论
那么我们在这里学到了什么?考虑到它/proc
被称为伪文件系统,也是“内部数据结构的接口”,因此可以安全地假设其中的项目是不是实际的文件,而只是看起来像文件的表现形式,但实际上不是。
我将以这句话作为结束语,它显然曾出现在大约 2004 年的先前版本中 man 5 proc
,但出于某种原因不再包含在内。笔记:我不知道为什么它被删除,因为它很好地描述了什么/proc
:
GNU/Linux 系统上的 /proc 目录提供了一个类似文件系统的内核接口。这允许应用程序和用户使用正常的文件系统 I/O 操作从内核获取信息并在内核中设置值。
proc 文件系统有时被称为进程信息伪文件系统。它不包含“真实”文件,而是包含运行时系统信息(例如系统内存、安装的设备、硬件配置等)。因此,它可以被视为内核的控制和信息中心。事实上,相当多的系统实用程序只是调用该目录中的文件。例如,命令 lsmod 列出了内核加载的模块,与“cat /proc/modules”基本相同,而 lspci 命令列出了连接到系统 PCI 总线的设备,与“cat /”相同。 proc/pci'。通过更改此目录中的文件,您可以在系统运行时更改内核参数。
来源: proc 伪文件系统
参考
答案3
@slm给出的答案非常全面,但我认为更简单的解释可能来自于视角的改变。
在日常使用中,我们可以将文件视为物理事物,即。存储在某些设备上的数据块。这使得 /proc/cpuinfo 这样的文件变得非常神秘和令人困惑。然而,如果我们将文件视为一个界面;一种将数据传入和传出某些程序的方法。
以这种方式发送和接收数据的程序是文件系统或驱动程序(取决于您如何定义这些术语,定义可能太宽泛或太窄)。重要的一点是一些这些程序使用硬件设备来存储和检索通过该接口发送的数据;但不是所有的。
文件系统的一些示例不使用存储设备(至少直接)是:
- 使用查找或计算数据的文件系统。 Proc 就是一个例子,因为它从各个内核模块获取数据。一个极端的例子是 πfs ( github.com/philipl/pifs )
- 所有 FUSE 文件系统,使用常规用户空间程序处理数据
- 即时转换另一个文件系统数据的文件系统,例如使用加密、压缩甚至音频转码( khenriks.github.io/mp3fs/ )
Plan9 操作系统 (http://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs)是使用文件作为通用编程接口的一个极端示例。