有许多文件/proc
,如/proc/cpuinfo
,/proc/meminfo
,/proc/devices
等等,其中,打开时,返回系统信息。
这些文件在现实中似乎不存在,因为file
在它们上运行只会表明它们是空的。
$ file /proc/cpuinfo
/proc/cpuinfo: empty
Run Code Online (Sandbox Code Playgroud)
这些文件究竟是如何工作的?
use*_*ser 77
它实际上非常简单,至少如果您不需要实现细节。
首先,在 Linux 上,所有文件系统(ext2、ext3、btrfs、reiserfs、tmpfs、zfs...)都在内核中实现。有些可能通过 FUSE 将工作卸载到用户态代码,有些仅以内核模块的形式出现(由于许可限制,原生 ZFS是后者的一个显着例子),但无论哪种方式,都保留了内核组件。这是一个重要的基础。
当程序想要从文件中读取时,它会发出各种系统库调用,这些调用最终以open()
, read()
,close()
序列的形式出现在内核中(seek()
为了更好的测量,可能会抛出)。内核采用提供的路径和文件名,并通过文件系统和设备 I/O 层将这些转换为物理读取请求(在许多情况下还包括写入请求——例如 atime 更新)到一些底层存储。
但是,它不必专门将这些请求转换为物理持久存储。内核的约定是发出一组特定的系统调用将提供相关文件的内容。在我们的物理领域中,“文件”存在的确切位置是次要的。
在/proc
通常安装所谓的procfs
。这是一种特殊的文件系统类型,但由于它是一个文件系统,它确实与例如ext3
安装在某处的文件系统没有什么不同。所以请求被传递到 procfs 文件系统驱动程序代码,它知道所有这些文件和目录,并从内核数据结构返回特定的信息片段。
在这种情况下,“存储层”是内核数据结构,它procfs
提供了一个干净、方便的接口来访问这些数据结构。请记住,将 procfs 挂载/proc
为简单的约定;您可以轻松地将其安装在其他地方。事实上,有时会这样做,例如在 chroot jails 中,当运行在那里的进程出于某种原因需要访问 /proc 时。
如果您将值写入某个文件,它的工作方式相同;在内核级别,这转化为一系列open()
, seek()
, write()
,close()
调用,这些调用再次传递给文件系统驱动程序;再次,在这种特殊情况下,procfs 代码。
您看到file
返回的特定原因empty
是 procfs 公开的许多文件都以0 字节的大小公开。0 字节大小可能是内核方面的优化(/proc 中的许多文件是动态的,长度很容易变化,甚至可能从一次读取到下一次读取,并且计算每个目录读取的每个文件的长度会可能非常昂贵)。根据对此答案的评论,您可以通过运行 strace 或类似工具在您自己的系统上进行验证,file
首先发出stat()
调用以检测任何特殊文件,然后如果文件大小报告为 0,则借此机会, 中止并报告文件为空。
这种行为实际上是记录,并可以通过指定覆盖-s
或--special-files
上file
调用,尽管在可能有副作用的手册页说明。以下引用来自 BSD 文件 5.11 手册页,日期为 2011 年 10 月 17 日。
通常,file 仅尝试读取和确定 stat(2) 报告为普通文件的参数文件的类型。这可以防止出现问题,因为读取特殊文件可能会产生特殊的后果。指定该
-s
选项会导致 file 还读取作为块或字符特殊文件的参数文件。这对于确定原始磁盘分区中数据的文件系统类型非常有用,这些数据是块特殊文件。 此选项还会导致 file 忽略 stat(2) 报告的文件大小,因为在某些系统上它报告原始磁盘分区的大小为零。
std*_*err 17
在此目录中,您可以控制内核如何查看设备、调整内核设置、向内核添加设备以及再次删除它们。在这个目录下可以直接查看内存使用情况和I/O统计。
您可以查看挂载了哪些磁盘以及使用了哪些文件系统。简而言之,如果您知道要查找的内容,则可以从该目录中检查 Linux 系统的每个方面。
该/proc
目录不是普通目录。如果您要从引导 CD 引导并查看硬盘驱动器上的该目录,您会看到它是空的。当您在正常运行的系统下查看它时,它可能非常大。但是,它似乎没有使用任何硬盘空间。这是因为它是一个虚拟文件系统。
由于/proc
文件系统是一个虚拟文件系统并驻留在内存中,/proc
因此每次 Linux 机器重新启动时都会创建一个新的文件系统。
换句话说,它只是一种通过文件和目录类型界面轻松窥视和窥探 Linux 系统内部结构的手段。当您查看/proc
目录中的文件时,您正在直接查看 Linux 内核中的内存范围,并查看它可以看到的内容。
文件系统中的层
例子:
/proc
,每个正在运行的进程都有一个目录,以其进程 ID 命名。这些目录包含具有有关进程的有用信息的文件,例如:
exe
:这是启动进程的磁盘上文件的符号链接。 cwd
: 这是进程工作目录的符号链接。wchan
: 读取时,返回进程所在的等待通道。maps
:读取时返回进程的内存映射。/proc/uptime
将正常运行时间返回为以秒为单位的两个十进制值,用空格分隔:
/proc/interrupts
: 有关中断的信息。/proc/modules
: 模块列表。有关更多详细信息,请参阅man proc或kernel.org。
你是对的,它们不是真正的文件。
简单来说,它是一种使用读写文件的正常方法与内核对话的方式,而不是直接调用内核。它符合 Unix 的“一切都是文件”的理念。
中的文件/proc
实际上并不存在于任何地方,但内核会对您在其中读取和写入的文件做出反应,而不是写入存储,而是报告信息或执行某些操作。
类似地,其中的文件/dev
并不是传统意义上的真正文件(尽管在某些系统上,其中的文件/dev
实际上可能存在于磁盘上,但除了它们所指的设备外,它们对它们没有任何意义)-它们使您能够交谈到使用普通 Unix 文件 I/O API 的设备 - 或任何使用它的设备,如 shell
创建新 procfs 条目的最小可运行示例
在我看来,理解这些事情的最好方法是实际使用它们,所以这里是一个创建 procfs 条目的内核模块:
myprocfs.c
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h> /* seq_read, seq_lseek, single_open, single_release */
#include <uapi/linux/stat.h> /* S_IRUSR */
static const char *filename = "lkmc_procfs";
static int show(struct seq_file *m, void *v)
{
seq_printf(m, "abcd\n");
return 0;
}
static int open(struct inode *inode, struct file *file)
{
return single_open(file, show, NULL);
}
static const struct file_operations fops = {
.llseek = seq_lseek,
.open = open,
.owner = THIS_MODULE,
.read = seq_read,
.release = single_release,
};
static int myinit(void)
{
proc_create(filename, 0, NULL, &fops);
return 0;
}
static void myexit(void)
{
remove_proc_entry(filename, NULL);
}
module_init(myinit)
module_exit(myexit)
MODULE_LICENSE("GPL");
Run Code Online (Sandbox Code Playgroud)
然后我们与它交互如下:
insmod procfs.ko
cat /proc/lkmc_procfs
Run Code Online (Sandbox Code Playgroud)
并产生输出:
abcd
Run Code Online (Sandbox Code Playgroud)
从这个例子中,我们清楚地看到proc
文件允许我们实现任意“文件相关的系统调用”,例如open
、read
和llseek
。
然后,这些系统调用可用于与内核进行任意通信。
因此,这些文件不需要与文件系统中的实际文件有任何关系,几乎所有文件都是如此。
例如,在我们的小示例中,我们只是创建一个read
始终返回的无用文件abcd\n
。
这是我的全自动 QEMU + Buildroot 设置,可以轻松安全地构建和使用此内核模块:
其他一些类似的接口包括:
debugfs 提供基本上完全相同的接口,但表明 API 不太稳定,这里是一个示例。
字符设备也非常相似,但文件是使用创建的mknod
,例如: https: //unix.stackexchange.com/questions/37829/how-do-character-device-or-character-special-files-work/371758# 371758
sysfs 是另一个更受限制的选项,请参阅此答案以获取更多详细信息:https://unix.stackexchange.com/questions/4884/what-is-the-difference- Between-procfs-and-sysfs/382315#382315