procfs¶
procfs 由内核生成,通过 VFS 挂载在 /proc;不需要用户态守护进程。
文件描述已有内核对象和策略。未实现的 Linux 子系统不会因为增加一个同名文件
而获得相应功能。
系统视图¶
路径 |
内容与边界 |
|---|---|
|
调度器的 1/5/15 分钟 Q16 负载、可运行/存活任务数、最近分配的 PID。 |
|
总计及每 CPU 的 user/system/idle、外部中断总数、上下文切换、启动时间、 创建任务数和当前可运行任务数。 |
|
物理内存总量/空闲量、页缓存、tmpfs、Dirty 和已启用 swap 容量。
|
|
空闲/缓存/tmpfs 页数、实际物理页分配/释放、逻辑用户 fault、换入/换出、 direct/background 回收及 OOM kill 信号发布计数。 |
|
已发布 swap 文件/分区的保留路径、KiB 容量/使用量及优先级,包含正在 drain 的区域;每次打开捕获固定视图。激活条件见 Swap。 |
|
当前注册整盘、GPT/MBR 分区和光驱的设备号、KiB 容量及设备名称。 |
|
整盘和光驱的实际块传输统计,采用 Linux 原始的 11 个统计字段。 |
|
每 CPU 实际收到的非零外部中断向量;不输出处理函数地址。 |
|
核心网卡服务观察到的收发字节/包/错误,以及本地 UDP 的 loopback 统计。 |
|
loopback、已配置直连子网/默认网关,以及现存 ARP 缓存;读取不发起探测。 |
|
现有端点、协议状态、实际队列、所有者和数值 inode;UNIX 地址支持抽象名。 |
CPU 时间以 100 Hz 调度 tick 结算,在 syscall、用户页错误和返回用户态的边界
区分 user/system。它不是高精度的 IRQ、softirq 或 iowait 计时;尚无独立记账的
CPU 列为零。当前阻塞任务均为可中断等待,procs_blocked 不将它们冒充为
Linux 的 D 状态。任务和创建计数包含线程。
diskstats 的扇区单位始终为 512 字节,包括 2048 字节块的光驱。
成功完成的传输才增加读写次数和扇区数;错误不算成功,EAGAIN 重试不重复
累计成功传输。进行中请求、读写耗时、忙碌毫秒及加权毫秒来自真实请求生命周期;
取消会移除进行中请求。没有请求合并层,合并计数为零;没有分区、discard 或
flush 的独立统计行/扩展字段。同步统计不分配内存;异步记账记录分配失败时
不改变 I/O 返回值,但该请求的等待时间无法完整保留。
partitions 解析未缓存的分区表时可能进行元数据 I/O,并返回真实传输错误。
进程与线程¶
/proc/self 指向调用者 TGID,/proc/thread-self 指向
TGID/task/TID。根目录枚举线程组首领;存活线程也可直接通过 /proc/TID
访问。/proc/PID/task 仅枚举该线程组,拒绝外组 TID、数字溢出以及递归
task/TID/task。显式线程视图不再列出 task 子目录。
下面的叶节点同样适用于 /proc/PID/task/TID 和 /proc/thread-self:
叶节点 |
内容 |
|---|---|
|
名称、状态、四组 UID/GID、补充组、umask、虚拟/RSS/代码/数据/栈/锁定内存、 线程数、信号掩码、capability、NoNewPrivs 和 CPU 亲和性。 |
|
Linux 顺序的 52 个字段;user/system tick 分开,进程视图汇总存活组成员, 显式线程视图只读一个线程;保留原有敏感地址字段的权限过滤。 |
|
以 4096 字节页为单位的虚拟量、RSS、共享映射、代码与数据/栈。 |
|
按地址排序的 VMA、权限、完整文件偏移、实际设备号/inode,以及持有对象的 当前路径或 deleted 后缀;匿名区域标注 heap/stack/vDSO/vvar。 |
|
逐区域或汇总的 RSS/PSS、共享/私有 clean/dirty、Referenced、Anonymous、 Locked;swap 和未支持的匿名大页统计为零。 |
|
内核支持的八项资源限制:文件数、地址空间、待处理信号、栈、进程数、 core 大小、锁定内存和普通文件大小;不虚构其他 rlimit。 |
|
exec 构造的二进制 |
|
已终结的 read/pread/readv/preadv/preadv2 及对应 write 调用数、成功字符数, 以及调用上下文中成功块传输的字节数。 |
|
共享 OFD 的位置、用户可见打开标志、该描述符的 CLOEXEC、mount ID/inode, 以及 eventfd/timerfd/epoll 的专项元数据;读取不消费事件或推进定时器。 |
PSS 通过遍历实际用户 PTE,按物理页的用户映射数分摊;共享同一地址空间的
CLONE_VM 线程只统计一次,缓存引用和内核引用不增加分母。设备映射不计入
普通驻留页。Dirty/Referenced 来自页表标志。读取 smaps 需要扫描各地址空间,
并为映射计数分配临时存储,可能返回 ENOMEM。
进程 io 汇总存活组成员,显式线程路径只显示相应线程。阻塞重试不会重复
计为用户调用;终结错误计为一次调用但不增加字符数。当前不包含 send/recv、
sendfile 等全部 Linux I/O 记账,也不保留已回收线程的历史组内累计值。
cancelled_write_bytes 为零,因为当前没有延迟脏页写回抵消记账。
网络表、socket fdinfo、fd 链接及 fstat 使用一致的数值 inode。
这些标识来自对象序号/句柄,不是内核指针,也不保证跨启动稳定。
权限与读取语义¶
maps、smaps、smaps_rollup、auxv、io 和 fdinfo 复用
现有的 proc FSCREDS/dumpable/CAP_SYS_PTRACE 检查。仅 UID 0 不构成绕过。
PID inode 保留任务身份令牌,PID 被复用后不会自动指向新任务。
新增文本文件及二进制 auxv 在成功打开时完整生成一份 OFD 快照;权限也在该时点
检查。随后短读、seek、EOF 均基于这份快照,进程退出或数据变化不拼接两代输出。
dup 共享已打开的视图,重新打开会生成新视图。快照不采用固定 4 KiB 截断;
分配失败返回 ENOMEM。这与 Linux 各 proc 文件的实时/seq_file 行为存在差异。
原有 cmdline、environ、mount view 和诊断文件仍遵守各自既有读取规则。
/proc/sys/fs/inotify 下的控制值在读取时取当前策略,不使用打开时快照。
策略节点¶
以下节点是现行内核策略的只读快照,不支持通过写文件调整:
/proc/sys/kernel/pid_max:非零 32 位 PID 命名空间上限。/proc/sys/fs/nr_open:描述符实现上限。/proc/sys/fs/file-nr:实际已分配 OFD、零个闲置预分配 OFD、全局上限。 dup/fork 别名不重复计数,排队、映射或进行中 I/O 保留的 OFD 直到最终释放才减计数。/proc/sys/fs/file-max:没有额外全局 OFD 数量配额,以UINT64_MAX表示; 仍受内存和每进程 rlimit 限制。/proc/sys/fs/pipe-max-size、pipe-user-pages-soft、pipe-user-pages-hard: 来自管道实现的现行容量、软限制及零值的未设置硬限制。
/proc/sys/fs/inotify/{max_user_instances,max_user_watches,max_queued_events}
是可写策略,root 可调整实例、监听和新队列的容量,普通用户只读。
默认值、超限错误及事件丢失恢复见 文件事件通知。
验证入口¶
tools/test_procfs.py 在 ASan/UBSan 下运行真实 proc/VFS 和 fdinfo 实现,覆盖
枚举、线程成员关系、权限、PSS、auxv、长快照、seek/EOF 与分配失败。
CPU、块设备、UDP/TCP/UNIX 和描述符生命周期由各自宿主测试覆盖。
tools/tests/procfs_probe.c 可在原生 Linux 上作为 ABI 参考运行,也可由操作系统
使用其 SDK 编译后放入 ReliefNT 来宾执行;Linux 参考通过不能视为来宾验收。
tools/tests/procfs_raw_probe.c 是无需 libc 的 x86-64 syscall 探针,编译参数
见文件头。它可作为小型 initramfs 的 /init,通过 rdinit=/init 启动,
在串口输出节点短读、seek/EOF、maps/PSS、auxv、线程目录、克隆后的
thread-self、fdinfo 和真实 UDP 接收队列的验收结果。作为 PID 1 时,探针
输出结果后等待,不退出触发内核 panic。相同源码也由宿主 procfs 套件在
Linux 上运行;队列检查兼容 Linux 缓冲区占用与 ReliefNT 有效载荷字节的差异。