Answers:
实际上,这非常简单,至少在不需要实现细节的情况下。
首先,在Linux上,所有文件系统(ext2,ext3,btrfs,reiserfs,tmpfs,zfs等)都在内核中实现。有些可以通过FUSE卸载工作到用户级代码,而有些则仅以内核模块的形式出现(由于许可限制,本机ZFS是后者的一个显着示例),但是无论哪种方式都保留了内核组件。这是重要的基础。
当一个程序需要从文件中读取,它会发出不同的系统库调用,最终结束了在内核中的形式open()
,read()
,close()
序列(可能seek()
抛出的良好措施)。内核采用提供的路径和文件名,并通过文件系统和设备I / O层将其转换为对某些底层存储的物理读取请求(在许多情况下,还包括写入请求-例如考虑进行时间更新)。
但是,不必将这些请求专门转换为物理,持久性存储。内核的约定是发出特定的系统调用集将提供有关文件的内容。在我们的物理领域中确切存在“文件”的位置是此位置的第二位。
在/proc
通常安装所谓的procfs
。这是一种特殊的文件系统类型,但是由于它是文件系统,因此它与ext3
安装在某处的文件系统没有什么不同。因此,该请求将传递到procfs文件系统驱动程序代码,该代码了解所有这些文件和目录,并从内核数据结构返回特定的信息。
在这种情况下,“存储层”是内核数据结构,并procfs
提供了一个干净,方便的接口来访问它们。请记住,将procfs挂接起来/proc
只是惯例。您可以轻松地将其安装在其他位置。实际上,有时这样做是可以的,例如在chroot监狱中,当运行于此的进程出于某种原因需要访问/ proc时。
如果您将值写入某个文件,则其工作方式相同。在内核级别,即转化为一系列open()
,seek()
,write()
,close()
电话再次获得通过文件系统驱动程序; 同样,在这种特殊情况下,还会显示procfs代码。
您看到file
返回的特定原因empty
是,procfs公开的许多文件公开的大小为0字节。0字节大小可能是内核方面的一种优化(/ proc中的许多文件都是动态的,并且长度很容易变化,甚至从一个读取到下一个都可能变化,并且计算每个目录读取时每个文件的长度会可能非常昂贵)。对该注释进行评论,您可以通过运行strace或类似工具在您自己的系统上进行验证,然后file
首先发出一个stat()
调用以检测任何特殊文件,然后趁此机会报告文件大小是否为0 ,中止并将文件报告为空。
该行为实际上已记录在案,并且可以通过指定-s
或--special-files
在file
调用中予以覆盖,尽管如手册页中所述可能会有副作用。下面的引用来自2011年10月17日的BSD文件5.11手册页。
通常,文件仅尝试读取并确定stat(2)报告为普通文件的参数文件的类型。这可以防止出现问题,因为读取特殊文件可能会产生特殊的后果。指定该
-s
选项会使文件还读取作为块或字符特殊文件的参数文件。这对于确定原始磁盘分区(即块特殊文件)中数据的文件系统类型很有用。 此选项还导致文件忽略stat(2)报告的文件大小,因为在某些系统上它报告原始磁盘分区的大小为零。
file
。这样,文件会预先加载魔术文件,然后逐个参数处理命令行参数;而不是将加载的魔术文件移动到代码的“尝试确定此特定文件属于哪种文件之前”部分,这会增加复杂性。调用stat()
并根据其返回值采取行动基本上是无害的;增加跟踪其他内部状态风险的复杂性,从而导致引入错误。
file
报告“文件为空” 的原因是因为它调用stat
来检测特殊文件(命名管道,设备等),并借此机会停止处理空文件。file -s /proc/version
报告“ ASCII文本”。
-s
应该用于块/字符特殊设备。最终,我查看了file
源代码,并在fsmagic.c的末尾看到了为什么它返回ASCII text
而不是返回的解释empty
:If stat() tells us the file has zero length, report here that the file is empty, so we can skip all the work of opening and reading the file. But if the -s option has been given, we skip this optimization, since on some systems, stat() reports zero size for raw disk partitions.
在此目录中,您可以控制内核如何查看设备,调整内核设置,将设备添加到内核并再次删除它们。在此目录中,您可以直接查看内存使用情况和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。
mount -t procfs procfs /mnt/proc
,则将看到当前正在运行的内核的/ proc。
您是正确的,它们不是真实文件。
用最简单的术语来说,这是一种使用常规读写文件的方法与内核进行通讯的方法,而不是直接调用内核。这符合Unix的“一切都是文件”的哲学。
其中的文件/proc
实际上并不存在,但是内核会对您在其中读取和写入的文件做出反应,而不是写入存储,而是报告信息或执行某些操作。
同样,其中的文件/dev
也不是传统意义上的文件(尽管在某些系统上,其中的文件/dev
可能实际存在于磁盘上,但它们所指的设备对它们没有太多影响)-它们使您可以交谈到使用普通Unix文件I / O API的设备-或使用它的任何设备(如外壳)
/proc
目录内部有两种类型的内容,第一种是编号目录,第二种是系统信息文件。
/proc
是一个虚拟文件系统。例如,如果您这样做了ls -l /proc/stat
,您会注意到它的大小为0个字节,但是如果您执行“ cat / proc / stat”,则您将在文件中看到一些内容。
进行ls -l /proc
,您会看到很多目录只有数字。这些数字代表进程ID(PID)。该编号目录内的文件与具有该特定PID的进程相对应。
在之下可用的某些文件/proc
包含系统信息,例如cpuinfo,meminfo和loadavg。
一些Linux命令从这些/proc
文件中读取信息并显示它。例如,free命令从/proc/meminfo
文件中读取内存信息,对其进行格式化并显示。
要了解有关单个/proc
文件的更多信息,请执行“ man 5 FILENAME”。
/proc/cmdline – Kernel command line
/proc/cpuinfo – Information about the processors.
/proc/devices – List of device drivers configured into the currently running kernel.
/proc/dma – Shows which DMA channels are being used at the moment.
/proc/fb – Frame Buffer devices.
/proc/filesystems – File systems supported by the kernel.
/proc/interrupts – Number of interrupts per IRQ on architecture.
/proc/iomem – This file shows the current map of the system’s memory for its various devices
/proc/ioports – provides a list of currently registered port regions used for input or output communication with a device
/proc/loadavg – Contains load average of the system
The first three columns measure CPU utilization of the last 1, 5, and 10 minute periods.
The fourth column shows the number of currently running processes and the total number of processes.
The last column displays the last process ID used.
/proc/locks – Displays the files currently locked by the kernel
Sample line:
1: POSIX ADVISORY WRITE 14375 08:03:114727 0 EOF
/proc/meminfo – Current utilization of primary memory on the system
/proc/misc – This file lists miscellaneous drivers registered on the miscellaneous major device, which is number 10
/proc/modules – Displays a list of all modules that have been loaded by the system
/proc/mounts – This file provides a quick list of all mounts in use by the system
/proc/partitions – Very detailed information on the various partitions currently available to the system
/proc/pci – Full listing of every PCI device on your system
/proc/stat – Keeps track of a variety of different statistics about the system since it was last restarted
/proc/swap – Measures swap space and its utilization
/proc/uptime – Contains information about uptime of the system
/proc/version – Version of the Linux kernel, gcc, name of the Linux flavor installed.
最小的可运行示例
我认为理解这些东西的最好方法是实际使用它们,因此下面是一个创建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");
然后我们以如下方式与它进行交互:
insmod procfs.ko
cat /proc/lkmc_procfs
并产生输出:
abcd
从这个例子中,我们清楚地看到,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
strace file /proc/version
或观看时ltrace -S /proc/version
,优化效果很小。它先执行一个stat()
调用,然后发现大小为0,从而跳过open()
-,但是在此之前它会加载多个魔术文件。