<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>虚拟文件系统 on 大飞的博客</title>
    <link>https://www.dafei.me/tags/%E8%99%9A%E6%8B%9F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/</link>
    <description>Recent content in 虚拟文件系统 on 大飞的博客</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Thu, 14 May 2026 03:00:00 +0000</lastBuildDate>
    <atom:link href="https://www.dafei.me/tags/%E8%99%9A%E6%8B%9F%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>从零写OS（二十三）：procfs 进程文件系统</title>
      <link>https://www.dafei.me/posts/os-23-procfs/</link>
      <pubDate>Thu, 14 May 2026 03:00:00 +0000</pubDate>
      <guid>https://www.dafei.me/posts/os-23-procfs/</guid>
      <description>&lt;p&gt;上一章有了 pipe 和 fd，现在进程可以互相传数据了。但还有一个问题：用户程序没有办法查询&amp;quot;系统里现在有哪些进程&amp;quot;——这类信息只存在内核里，外面拿不到。&lt;/p&gt;
&lt;p&gt;加专用 syscall 当然可以，但 Linux 选择了一个更优雅的方案：&lt;strong&gt;procfs&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一切皆文件&#34;&gt;一切皆文件&lt;/h2&gt;
&lt;p&gt;procfs 的思路是：把内核状态&lt;strong&gt;伪装成文件&lt;/strong&gt;，挂在 &lt;code&gt;/proc/&lt;/code&gt; 目录下。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;/proc/0/status   → 进程 0 的信息
/proc/1/status   → 进程 1 的信息
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;用户程序用完全一样的 &lt;code&gt;open/read/close&lt;/code&gt; 就能读到，不需要学新 API：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt; fd &lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt; &lt;span style=&#34;color:#a6e22e&#34;&gt;open&lt;/span&gt;(&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/proc/1/status&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a6e22e&#34;&gt;read&lt;/span&gt;(fd, buf, &lt;span style=&#34;color:#ae81ff&#34;&gt;128&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#75715e&#34;&gt;// buf 里是 &amp;#34;pid: 1\nstate: running\nparent: 0\n&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这就是 Linux &amp;ldquo;一切皆文件&amp;rdquo; 哲学的体现——统一接口，背后实现可以完全不同。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;虚拟文件和真实文件的区别&#34;&gt;虚拟文件和真实文件的区别&lt;/h2&gt;
&lt;p&gt;普通文件的 &lt;code&gt;read&lt;/code&gt;：从磁盘读数据。&lt;/p&gt;
&lt;p&gt;procfs 文件的 &lt;code&gt;read&lt;/code&gt;：&lt;strong&gt;内核现场生成内容&lt;/strong&gt;，没有磁盘，没有 inode，数据就是 &lt;code&gt;procs[]&lt;/code&gt; 数组里的字段格式化出来的字符串。&lt;/p&gt;
&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;open(&amp;#34;/proc/1/status&amp;#34;)
  → vfs_open 识别 &amp;#34;/proc/&amp;#34; 前缀
  → procfs_open 解析 pid，格式化状态字符串存入内核 buf
  → 返回 VFile（type=VFILE_PROC）

read(fd, buf, len)
  → vfs_read 识别 VFILE_PROC
  → 从内核 buf 按 offset 拷贝给用户
&lt;/code&gt;&lt;/pre&gt;&lt;hr&gt;
&lt;h2 id=&#34;实现&#34;&gt;实现&lt;/h2&gt;
&lt;h3 id=&#34;procfs-内核结构&#34;&gt;procfs 内核结构&lt;/h3&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#66d9ef&#34;&gt;struct&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;int&lt;/span&gt;      used;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; pid;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;char&lt;/span&gt;     buf[&lt;span style=&#34;color:#ae81ff&#34;&gt;256&lt;/span&gt;];   &lt;span style=&#34;color:#75715e&#34;&gt;// open 时格式化好的字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; buf_len;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#66d9ef&#34;&gt;uint32_t&lt;/span&gt; offset;     &lt;span style=&#34;color:#75715e&#34;&gt;// 支持分段 read
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} &lt;span style=&#34;color:#66d9ef&#34;&gt;proc_fd_t&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;open&lt;/code&gt; 时一次性生成完整字符串，后续 &lt;code&gt;read&lt;/code&gt; 只是按 offset 切片拷贝——和普通文件行为完全一致，可以多次 read。&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
