/proc 文件系统

/proc/sys

Terrehon Bowden <terrehon@pacbell.net>, Bodo Bauer <bb@ricochet.net>

1999 年 10 月 7 日

2.4.x 更新

Jorge Nerin <comandante@zaralinux.com>

2000 年 11 月 14 日

移动 /proc/sys

沈峰 <shen@cn.fujitsu.com>

2009 年 4 月 1 日

修复/更新 1.1 部分

Stefani Seibold <stefani@seibold.net>

2009 年 6 月 9 日

前言

0.1 简介/致谢

本文档是关于 SuSE Linux 发行版的书的一部分(我们希望很快就会发布)。由于没有关于 /proc 文件系统的完整文档,并且我们使用了许多免费的资源来编写这些章节,因此将这项工作回馈给 Linux 社区似乎是公平的。这项工作基于 2.2.* 内核版本和即将到来的 2.4.*。恐怕它还远未完成,但我们希望它会有用。据我们所知,它是第一个关于 /proc 文件系统的“一体式”文档。它专注于 Intel x86 硬件,因此如果您正在寻找 PPC、ARM、SPARC、AXP 等功能,您可能找不到您要找的东西。它也只涵盖 IPv4 网络,不包括 IPv6 或其他协议 - 对不起。但是欢迎添加和补丁,如果您将它们邮寄给 Bodo,它们将被添加到本文档中。

我们要感谢 Alan Cox、Rik van Riel 和 Alexey Kuznetsov 以及许多其他人为编译本文档提供的帮助。我们还要特别感谢 Andi Kleen 的文档,我们主要依靠它来创建本文档,以及他提供的其他信息。感谢其他所有为 Linux 内核贡献源代码或文档并帮助创建出色的软件的人... :)

如果您有任何意见、更正或补充,请随时通过 bb@ricochet.net 联系 Bodo Bauer。 我们很乐意将它们添加到本文档中。

本文档的最新版本可在网上找到:https://linuxkernel.org.cn/doc/html/latest/filesystems/proc.html

如果以上链接对您不起作用,您可以尝试内核邮件列表:linux-kernel@vger.kernel.org 和/或尝试通过 comandante@zaralinux.com 联系我。

第 1 章:收集系统信息

本章内容

  • 研究伪文件系统 /proc 的属性及其提供有关正在运行的 Linux 系统的信息的能力

  • 检查 /proc 的结构

  • 揭示有关内核和系统上运行的进程的各种信息


proc 文件系统充当内核中内部数据结构的接口。它可用于获取有关系统的信息,并在运行时更改某些内核参数 (sysctl)。

首先,我们将看看 /proc 的只读部分。在第 2 章中,我们将向您展示如何使用 /proc/sys 来更改设置。

1.1 进程特定的子目录

目录 /proc 包含(除其他外)系统中运行的每个进程的一个子目录,该子目录以进程 ID (PID) 命名。

链接“self”指向读取文件系统的进程。每个进程子目录都有表 1-1 中列出的条目。

请注意,如果 退出,则打开 /proc/ 或其包含的任何文件或子目录的文件描述符不会阻止 被重用于其他进程。对与死进程对应的打开 /proc/ 文件描述符的操作永远不会对内核可能通过偶然机会也分配了进程 ID 的任何新进程起作用。相反,对这些 FD 的操作通常会失败并返回 ESRCH。

表 1-1:/proc 中进程特定的条目

文件

内容

clear_refs

清除 smaps 输出中显示Page Referenced Bits

cmdline

命令行参数

cpu

当前和上次执行的 CPU (2.4)(smp)

cwd

指向当前工作目录的链接

environ

环境变量的值

exe

指向此进程可执行文件的链接

fd

目录,包含所有文件描述符

maps

到可执行文件和库文件的内存映射 (2.4)

mem

此进程持有的内存

root

指向此进程根目录的链接

stat

进程状态

statm

进程内存状态信息

status

人类可读形式的进程状态

wchan

存在 CONFIG_KALLSYMS=y 时:它显示任务被阻塞的内核函数符号 - 如果未阻塞,则显示“0”。

pagemap

页表

stack

报告完整的堆栈跟踪,通过 CONFIG_STACKTRACE 启用

smaps

基于 maps 的扩展,显示每个映射的内存消耗以及与之关联的标志

smaps_rollup

进程所有映射的累积 smaps 统计信息。这可以从 smaps 导出,但速度更快更方便

numa_maps

基于 maps 的扩展,显示每个映射的内存局部性和绑定策略以及内存使用情况(以页为单位)。

例如,要获取进程的状态信息,您所要做的就是读取文件 /proc/PID/status

>cat /proc/self/status
Name:   cat
State:  R (running)
Tgid:   5452
Pid:    5452
PPid:   743
TracerPid:      0                                             (2.4)
Uid:    501     501     501     501
Gid:    100     100     100     100
FDSize: 256
Groups: 100 14 16
Kthread:    0
VmPeak:     5004 kB
VmSize:     5004 kB
VmLck:         0 kB
VmHWM:       476 kB
VmRSS:       476 kB
RssAnon:             352 kB
RssFile:             120 kB
RssShmem:              4 kB
VmData:      156 kB
VmStk:        88 kB
VmExe:        68 kB
VmLib:      1412 kB
VmPTE:        20 kb
VmSwap:        0 kB
HugetlbPages:          0 kB
CoreDumping:    0
THP_enabled:    1
Threads:        1
SigQ:   0/28578
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 00000000fffffeff
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: ffffffffffffffff
CapAmb: 0000000000000000
NoNewPrivs:     0
Seccomp:        0
Speculation_Store_Bypass:       thread vulnerable
SpeculationIndirectBranch:      conditional enabled
voluntary_ctxt_switches:        0
nonvoluntary_ctxt_switches:     1

这会显示与使用 ps 命令查看时几乎相同的信息。事实上,ps 使用 proc 文件系统来获取其信息。但是,通过读取文件 /proc/PID/status,您可以获得进程的更详细视图。它的字段在表 1-2 中描述。

statm 文件包含有关进程内存使用情况的更详细信息。它的七个字段在表 1-3 中进行了解释。stat 文件包含有关进程本身的详细信息。它的字段在表 1-4 中进行了解释。

(对于 SMP CONFIG 用户)

为了使记帐具有可伸缩性,RSS 相关信息以异步方式处理,该值可能不是很精确。要查看某一时刻的精确快照,您可以查看 /proc//smaps 文件并扫描页表。它很慢但非常精确。

表 1-2:状态字段的内容(截至 4.19)

字段

内容

名称

可执行文件的文件名

Umask

文件模式创建掩码

状态

状态(R 表示正在运行,S 表示正在睡眠,D 表示在不可中断的等待中睡眠,Z 表示僵尸,T 表示被跟踪或停止)

Tgid

线程组 ID

Ngid

NUMA 组 ID(如果无,则为 0)

Pid

进程 ID

PPid

父进程的进程 ID

TracerPid

跟踪此进程的进程的 PID(如果不跟踪,或者跟踪器位于当前 pid 命名空间之外,则为 0)

Uid

实际 UID、有效 UID、保存集 UID 和文件系统 UID

Gid

实际 GID、有效 GID、保存集 GID 和文件系统 GID

FDSize

当前分配的文件描述符槽的数量

Groups

补充组列表

NStgid

后代命名空间线程组 ID 层次结构

NSpid

后代命名空间进程 ID 层次结构

NSpgid

后代命名空间进程组 ID 层次结构

NSsid

后代命名空间会话 ID 层次结构

Kthread

内核线程标志,1 为是,0 为否

VmPeak

峰值虚拟内存大小

VmSize

总程序大小

VmLck

锁定内存大小

VmPin

固定内存大小

VmHWM

峰值常驻集大小(“高水位线”)

VmRSS

内存部分的大小。它包含以下三个部分 (VmRSS = RssAnon + RssFile + RssShmem)

RssAnon

常驻匿名内存的大小

RssFile

常驻文件映射的大小

RssShmem

常驻 shmem 内存的大小(包括 SysV shm、tmpfs 映射和共享匿名映射)

VmData

私有数据段的大小

VmStk

堆栈段的大小

VmExe

文本段的大小

VmLib

共享库代码的大小

VmPTE

页表条目的大小

VmSwap

匿名私有数据使用的交换空间量(不包括 shmem 交换空间使用量)

HugetlbPages

hugetlb 内存部分的大小

CoreDumping

正在转储进程的内存(终止进程可能导致核心转储损坏)

THP_enabled

允许进程使用 THP(当在进程上设置 PR_SET_THP_DISABLE 时返回 0)

Threads

线程数

SigQ

排队的信号数/队列的最大数

SigPnd

线程的待处理信号的位图

ShdPnd

进程的共享待处理信号的位图

SigBlk

被阻塞的信号的位图

SigIgn

被忽略的信号的位图

SigCgt

捕获的信号的位图

CapInh

可继承的功能的位图

CapPrm

允许的功能位图

CapEff

有效的功能位图

CapBnd

功能边界集位图

CapAmb

环境功能位图

NoNewPrivs

no_new_privs,类似于 prctl(PR_GET_NO_NEW_PRIV, ...)

Seccomp

seccomp 模式,类似于 prctl(PR_GET_SECCOMP, ...)

Speculation_Store_Bypass

推测存储旁路缓解状态

SpeculationIndirectBranch

间接分支推测模式

Cpus_allowed

此进程可能运行的 CPU 掩码

Cpus_allowed_list

与前一个相同,但采用“列表格式”

Mems_allowed

允许此进程使用的内存节点掩码

Mems_allowed_list

与前一个相同,但采用“列表格式”

voluntary_ctxt_switches

自愿上下文切换次数

nonvoluntary_ctxt_switches

非自愿上下文切换次数

表 1-3:statm 字段的内容(截至 2.6.8-rc3)

字段

内容

size

程序总大小(页)

(与 status 中的 VmSize 相同)

resident

内存部分的大小(页)

(与 status 中的 VmRSS 相同)

shared

共享的页数

(即由文件支持,与 status 中的 RssFile+RssShmem 相同)

trs

“代码”的页数

(不包括库;已损坏,包括数据段)

lrs

库的页数

(在 2.6 上始终为 0)

drs

数据/堆栈的页数

(包括库;已损坏,包括库文本)

dt

脏页数

(在 2.6 上始终为 0)

表 1-4:stat 字段的内容(截至 2.6.30-rc7)

字段

内容

pid

进程 ID

tcomm

可执行文件的文件名

state

状态(R 表示正在运行,S 表示正在睡眠,D 表示在不可中断的等待中睡眠,Z 表示僵尸,T 表示被跟踪或停止)

ppid

父进程的进程 ID

pgrp

进程的 pgrp

sid

会话 ID

tty_nr

进程使用的 tty

tty_pgrp

tty 的 pgrp

flags

任务标志

min_flt

次要错误数

cmin_flt

子进程的次要错误数

maj_flt

主要错误数

cmaj_flt

子进程的主要错误数

utime

用户模式 jiffies

stime

内核模式 jiffies

cutime

子进程的用户模式 jiffies

cstime

子进程的内核模式 jiffies

priority

优先级

nice

nice 值

num_threads

线程数

it_real_value

(已过时,始终为 0)

start_time

进程在系统启动后开始的时间

vsize

虚拟内存大小

rss

常驻集内存大小

rsslim

rss 的当前字节限制

start_code

程序文本可以运行的起始地址

end_code

程序文本可以运行的结束地址

start_stack

主进程堆栈的起始地址

esp

ESP 的当前值

eip

EIP 的当前值

pending

待处理信号位图

blocked

被阻塞的信号的位图

sigign

被忽略的信号的位图

sigcatch

捕获的信号的位图

0

(占位符,曾经是 wchan 地址,请改用 /proc/PID/wchan)

0

(占位符)

0

(占位符)

exit_signal

退出时发送给父线程的信号

task_cpu

任务被调度到的 CPU

rt_priority

实时优先级

policy

调度策略(man sched_setscheduler)

blkio_ticks

等待块 IO 所花费的时间

gtime

任务的访客时间(以 jiffies 为单位)

cgtime

任务子进程的访客时间(以 jiffies 为单位)

start_data

程序数据 + bss 放置的起始地址

end_data

程序数据 + bss 放置的结束地址

start_brk

可以使用 brk() 扩展程序堆的起始地址

arg_start

程序命令行放置的起始地址

arg_end

程序命令行放置的结束地址

env_start

程序环境放置的起始地址

env_end

程序环境放置的结束地址

exit_code

由 waitpid 系统调用报告的线程的 exit_code 形式

/proc/PID/maps 文件包含当前映射的内存区域及其访问权限。

格式为

address           perms offset  dev   inode      pathname

08048000-08049000 r-xp 00000000 03:00 8312       /opt/test
08049000-0804a000 rw-p 00001000 03:00 8312       /opt/test
0804a000-0806b000 rw-p 00000000 00:00 0          [heap]
a7cb1000-a7cb2000 ---p 00000000 00:00 0
a7cb2000-a7eb2000 rw-p 00000000 00:00 0
a7eb2000-a7eb3000 ---p 00000000 00:00 0
a7eb3000-a7ed5000 rw-p 00000000 00:00 0
a7ed5000-a8008000 r-xp 00000000 03:00 4222       /lib/libc.so.6
a8008000-a800a000 r--p 00133000 03:00 4222       /lib/libc.so.6
a800a000-a800b000 rw-p 00135000 03:00 4222       /lib/libc.so.6
a800b000-a800e000 rw-p 00000000 00:00 0
a800e000-a8022000 r-xp 00000000 03:00 14462      /lib/libpthread.so.0
a8022000-a8023000 r--p 00013000 03:00 14462      /lib/libpthread.so.0
a8023000-a8024000 rw-p 00014000 03:00 14462      /lib/libpthread.so.0
a8024000-a8027000 rw-p 00000000 00:00 0
a8027000-a8043000 r-xp 00000000 03:00 8317       /lib/ld-linux.so.2
a8043000-a8044000 r--p 0001b000 03:00 8317       /lib/ld-linux.so.2
a8044000-a8045000 rw-p 0001c000 03:00 8317       /lib/ld-linux.so.2
aff35000-aff4a000 rw-p 00000000 00:00 0          [stack]
ffffe000-fffff000 r-xp 00000000 00:00 0          [vdso]

其中 “address” 是它占用的进程中的地址空间,“perms” 是一组权限

r = read
w = write
x = execute
s = shared
p = private (copy on write)

“offset” 是映射中的偏移量,“dev” 是设备(主:次),“inode” 是该设备上的 inode。 0 表示没有 inode 与内存区域关联,如 BSS(未初始化数据)的情况。 “pathname” 显示此映射的关联文件的名称。如果映射未与文件关联

[heap]

程序的堆

[stack]

主进程的堆栈

[vdso]

“虚拟动态共享对象”,内核系统调用处理程序

[anon:<name>]

由用户空间命名的私有匿名映射

[anon_shmem:<name>]

由用户空间命名的匿名共享内存映射

或者如果为空,则映射是匿名的。

从 6.11 内核开始,/proc/PID/maps 提供了一个基于 ioctl() 的替代 API,它能够灵活高效地查询和筛选单个 VMA。此接口是二进制的,旨在更高效且易于编程使用。struct procmap_query 在 linux/fs.h UAPI 标头中定义,用作 PROCMAP_QUERY ioctl() 命令的输入/输出参数。有关查询语义、支持的标志、返回的数据和常规 API 使用信息的详细信息,请参见 linus/fs.h UAPI 标头中的注释。

/proc/PID/smaps 是基于 maps 的扩展,显示进程每个映射的内存消耗。对于每个映射(又名虚拟内存区域或 VMA),都有一系列行,例如以下内容

08048000-080bc000 r-xp 00000000 03:02 13130      /bin/bash

Size:               1084 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Rss:                 892 kB
Pss:                 374 kB
Pss_Dirty:             0 kB
Shared_Clean:        892 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:          892 kB
Anonymous:             0 kB
KSM:                   0 kB
LazyFree:              0 kB
AnonHugePages:         0 kB
ShmemPmdMapped:        0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
THPeligible:           0
VmFlags: rd ex mr mw me dw

这些行的第一行显示与 /proc/PID/maps 中映射显示的信息相同的信息。随后的行显示映射的大小 (size);当支持 VMA 时分配的每个页面的大小 (KernelPageSize),这通常与页表条目中的大小相同;MMU 在支持 VMA 时使用的页面大小(在大多数情况下,与 KernelPageSize 相同);当前驻留在 RAM 中的映射量 (RSS);进程的此映射的比例份额 (PSS);以及映射中干净和脏的共享和私有页面的数量。

进程的“比例集大小”(PSS) 是它在内存中的页数计数,其中每个页面除以共享它的进程数。因此,如果一个进程拥有 1000 个页面,并且与另一个进程共享 1000 个页面,则其 PSS 为 1500。 “Pss_Dirty” 是由脏页组成的 PSS 部分。(“Pss_Clean” 未包括在内,但可以通过从 “Pss” 中减去 “Pss_Dirty” 来计算。)

请注意,即使是 MAP_SHARED 映射的一部分,但只有一个 pte 映射的页面,即当前仅由一个进程使用,也会被视为私有,而不是共享的。

“Referenced” 表示当前标记为引用或访问的内存量。

“Anonymous” 显示不属于任何文件的内存量。即使与文件关联的映射也可能包含匿名页面:当 MAP_PRIVATE 和页面被修改时,文件页面将替换为私有匿名副本。

“KSM” 报告有多少页面是 KSM 页面。请注意,不包括 KSM 放置的零页面,仅包括实际的 KSM 页面。

“LazyFree” 显示由 madvise(MADV_FREE) 标记的内存量。内存不会立即通过 madvise() 释放。如果内存是干净的,则会在内存压力下释放。请注意,由于当前实现中使用的优化,打印的值可能低于实际值。如果这不是您所期望的,请提交错误报告。

“AnonHugePages” 显示透明大页面支持的内存量。

“ShmemPmdMapped” 显示由大页面支持的共享 (shmem/tmpfs) 内存量。

“Shared_Hugetlb” 和 “Private_Hugetlb” 显示由 hugetlbfs 页面支持的内存量,出于历史原因,该内存量 计入 “RSS” 或 “PSS” 字段中。并且这些不包括在 {Shared,Private}_{Clean,Dirty} 字段中。

“Swap” 显示有多少曾经是匿名的内存也被使用,但现在在交换空间中。

对于 shmem 映射,“Swap” 还包括在交换空间中映射(而不是被写时复制替换)的底层 shmem 对象部分的大小。“SwapPss” 显示此映射的比例交换份额。与 “Swap” 不同,这不会考虑底层 shmem 对象中换出的页面。“Locked” 指示映射是否锁定在内存中。

“THPeligible” 指示映射是否符合分配任何当前启用大小的自然对齐 THP 页面的条件。如果为 true,则为 1,否则为 0。

“VmFlags” 字段值得单独描述。此成员以两个字母的编码方式表示与特定虚拟内存区域关联的内核标志。代码如下

rd

可读

wr

可写

ex

可执行

sh

shared

mr

可能读取

mw

可能写入

me

可能执行

ms

可能共享

gd

堆栈段向下增长

pf

纯 PFN 范围

dw

禁用对映射文件的写入

lo

页面锁定在内存中

io

内存映射 I/O 区域

sr

提供顺序读取建议

rr

提供随机读取建议

dc

不在 fork 上复制区域

de

不在重映射时扩展区域

ac

该区域是可核算的

nr

不为该区域保留交换空间

ht

该区域使用大 tlb 页面

sf

同步页面错误

ar

特定于体系结构的标志

wf

fork 时擦除

dd

不将区域包括在核心转储中

sd

软脏标志

mm

混合映射区域

hg

大页面建议标志

nh

无大页面建议标志

mg

可合并建议标志

bt

arm64 BTI 防护页面

mt

启用 arm64 MTE 分配标记

um

userfaultfd 缺少跟踪

uw

userfaultfd 写保护跟踪

ss

影子/受保护的控制堆栈页面

sl

已密封

请注意,不能保证所有标志和相关助记符都将出现在所有后续内核版本中。事情会发生变化,标志可能会消失,或者相反 - 添加新的标志。它们含义的解释也可能会在将来发生变化。因此,这些标志的每个使用者都必须遵循每个特定内核版本以了解确切的语义。

仅当启用 CONFIG_MMU 内核配置选项时,此文件才存在。

注意:读取 /proc/PID/maps 或 /proc/PID/smaps 本质上是存在竞争条件的(只有在单次读取调用中才能实现一致的输出)。

这通常在内存映射被修改时,对这些文件进行部分读取时发生。尽管存在竞争,我们仍然提供以下保证:

  1. 映射的地址永远不会倒退,这意味着任何两个区域都不会重叠。

  2. 如果在 smaps/maps 遍历的整个生命周期中,给定虚拟地址(vaddr)存在内容,那么肯定会有相应的输出。

/proc/PID/smaps_rollup 文件包含与 /proc/PID/smaps 相同的字段,但它们的值是该进程所有映射的对应值的总和。此外,它还包含以下字段:

  • Pss_Anon

  • Pss_File

  • Pss_Shmem

它们表示匿名、文件和共享内存页面的比例份额,如上述 smaps 所述。这些字段在 smaps 中被省略,因为每个映射都标识了它包含的所有页面的类型(匿名、文件或共享内存)。因此,smaps_rollup 中的所有信息都可以从 smaps 中导出,但成本要高得多。

/proc/PID/clear_refs 用于重置与进程关联的物理和虚拟页面上的 PG_Referenced 和 ACCESSED/YOUNG 位,以及 pte 上的软脏位(详情请参阅 软脏 PTE)。要清除与该进程关联的所有页面的位:

> echo 1 > /proc/PID/clear_refs

要清除与该进程关联的匿名页面的位:

> echo 2 > /proc/PID/clear_refs

要清除与该进程关联的文件映射页面的位:

> echo 3 > /proc/PID/clear_refs

要清除软脏位:

> echo 4 > /proc/PID/clear_refs

要将峰值常驻集大小(“最高水位线”)重置为该进程的当前值:

> echo 5 > /proc/PID/clear_refs

写入 /proc/PID/clear_refs 的任何其他值都不会产生任何效果。

/proc/pid/pagemap 提供 PFN,可用于使用 /proc/kpageflags 查找页面标志,并使用 /proc/kpagecount 查找页面被映射的次数。有关详细说明,请参阅 检查进程页表

/proc/pid/numa_maps 是基于 maps 的扩展,显示了内存局部性和绑定策略,以及每个映射的内存使用情况(以页为单位)。输出遵循一种通用格式,其中映射详细信息以空格分隔,每个文件行一个映射:

address   policy    mapping details

00400000 default file=/usr/local/bin/app mapped=1 active=0 N3=1 kernelpagesize_kB=4
00600000 default file=/usr/local/bin/app anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206000000 default file=/lib64/ld-2.12.so mapped=26 mapmax=6 N0=24 N3=2 kernelpagesize_kB=4
320621f000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206220000 default file=/lib64/ld-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206221000 default anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206800000 default file=/lib64/libc-2.12.so mapped=59 mapmax=21 active=55 N0=41 N3=18 kernelpagesize_kB=4
320698b000 default file=/lib64/libc-2.12.so
3206b8a000 default file=/lib64/libc-2.12.so anon=2 dirty=2 N3=2 kernelpagesize_kB=4
3206b8e000 default file=/lib64/libc-2.12.so anon=1 dirty=1 N3=1 kernelpagesize_kB=4
3206b8f000 default anon=3 dirty=3 active=1 N3=3 kernelpagesize_kB=4
7f4dc10a2000 default anon=3 dirty=3 N3=3 kernelpagesize_kB=4
7f4dc10b4000 default anon=2 dirty=2 active=1 N3=2 kernelpagesize_kB=4
7f4dc1200000 default file=/anon_hugepage\040(deleted) huge anon=1 dirty=1 N3=1 kernelpagesize_kB=2048
7fff335f0000 default stack anon=3 dirty=3 N3=3 kernelpagesize_kB=4
7fff3369d000 default mapped=1 mapmax=35 active=0 N3=1 kernelpagesize_kB=4

其中:

“address” 是映射的起始地址;

“policy” 报告为映射设置的 NUMA 内存策略(请参阅 NUMA 内存策略);

“mapping details” 汇总了映射数据,例如映射类型、页面使用计数器、节点局部性页面计数器(N0 == 节点 0,N1 == 节点 1,...)以及支持映射的内核页面大小(以 KB 为单位)。

1.2 内核数据

与进程条目类似,内核数据文件提供了有关正在运行的内核的信息。用于获取此信息的文件包含在 /proc 中,并在表 1-5 中列出。并非所有这些文件都会出现在您的系统中。这取决于内核配置和加载的模块,哪些文件存在,哪些文件缺失。

表 1-5:/proc 中的内核信息

文件

内容

allocinfo

内存分配分析信息

apm

高级电源管理信息

bootconfig

从启动配置获得的内核命令行,以及如果存在来自引导加载程序的内核参数,则会有一行 “# Parameters from bootloader:” 以及包含这些参数并以 “# ” 开头的一行。(5.5)

buddyinfo

内核内存分配器信息(见正文)(2.5)

bus

包含特定总线信息的目录

cmdline

内核命令行,来自引导加载程序和嵌入在内核映像中的命令行

cpuinfo

有关 CPU 的信息

devices

可用的设备(块设备和字符设备)

dma

使用的 DMS 通道

filesystems

支持的文件系统

driver

此处分组的各种驱动程序,当前是 rtc(2.4)

execdomains

与安全相关的执行域(2.4)

fb

帧缓冲设备(2.4)

fs

文件系统参数,当前为 nfs/exports(2.4)

ide

包含有关 IDE 子系统信息的目录

interrupts

中断使用情况

iomem

内存映射(2.4)

ioports

I/O 端口使用情况

irq

用于 irq 到 cpu 亲和性的掩码(2.4)(smp?)

isapnp

ISA PnP(即插即用)信息(2.4)

kcore

内核核心映像(可以是 ELF 或 A.OUT(在 2.4 中已弃用))

kmsg

内核消息

ksyms

内核符号表

loadavg

过去 1、5 和 15 分钟的平均负载;

当前可运行的进程数(正在运行或在就绪队列中);系统中的进程总数;最后创建的 pid。所有字段都用一个空格分隔,除了“当前可运行的进程数”和“系统中的进程总数”,它们用斜杠(‘/’)分隔。示例:0.61 0.61 0.55 3/828 22084

locks

内核锁

meminfo

内存信息

misc

杂项

modules

加载的模块列表

mounts

已挂载的文件系统

net

网络信息(见正文)

pagetypeinfo

其他页面分配器信息(见正文)(2.5)

partitions

系统已知的分区表

pci

已弃用的 PCI 总线信息(新方法 -> /proc/bus/pci/,由 lspci 解耦(2.4))

rtc

实时时钟

scsi

SCSI 信息(见正文)

slabinfo

Slab 池信息

softirqs

软中断使用情况

stat

总体统计信息

swaps

交换空间利用率

sys

请参阅第 2 章

sysvipc

SysVIPC 资源(msg、sem、shm)的信息(2.4)

tty

tty 驱动程序的信息

uptime

自启动以来的挂钟时间,结合所有 CPU 的空闲时间

version

内核版本

video

视频资源的 bttv 信息(2.4)

vmallocinfo

显示 vmalloc 区域

例如,您可以通过查看文件 /proc/interrupts 来检查当前正在使用哪些中断以及它们用于什么

> cat /proc/interrupts
           CPU0
  0:    8728810          XT-PIC  timer
  1:        895          XT-PIC  keyboard
  2:          0          XT-PIC  cascade
  3:     531695          XT-PIC  aha152x
  4:    2014133          XT-PIC  serial
  5:      44401          XT-PIC  pcnet_cs
  8:          2          XT-PIC  rtc
 11:          8          XT-PIC  i82365
 12:     182918          XT-PIC  PS/2 Mouse
 13:          1          XT-PIC  fpu
 14:    1232265          XT-PIC  ide0
 15:          7          XT-PIC  ide1
NMI:          0

在 2.4.* 中,此文件中添加了几行 LOC 和 ERR(此时是 SMP 机器的输出)

> cat /proc/interrupts

           CPU0       CPU1
  0:    1243498    1214548    IO-APIC-edge  timer
  1:       8949       8958    IO-APIC-edge  keyboard
  2:          0          0          XT-PIC  cascade
  5:      11286      10161    IO-APIC-edge  soundblaster
  8:          1          0    IO-APIC-edge  rtc
  9:      27422      27407    IO-APIC-edge  3c503
 12:     113645     113873    IO-APIC-edge  PS/2 Mouse
 13:          0          0          XT-PIC  fpu
 14:      22491      24012    IO-APIC-edge  ide0
 15:       2183       2415    IO-APIC-edge  ide1
 17:      30564      30414   IO-APIC-level  eth0
 18:        177        164   IO-APIC-level  bttv
NMI:    2457961    2457959
LOC:    2457882    2457881
ERR:       2155

在这种情况下,NMI 会增加,因为每个定时器中断都会生成一个 NMI(不可屏蔽中断),NMI Watchdog 使用该 NMI 来检测死锁。

LOC 是每个 CPU 内部 APIC 的本地中断计数器。

如果 IO-APIC 总线(连接 SMP 系统中 CPU 的总线)发生错误,则 ERR 会增加。这意味着已检测到错误,IO-APIC 会自动重试传输,因此这不应该是一个大问题,但您应该阅读 SMP-FAQ。

在 2.6.2* 中,/proc/interrupts 再次扩展。这一次的目标是让 /proc/interrupts 显示系统中正在使用的每个 IRQ 向量,而不仅仅是那些被认为是“最重要的”向量。新的向量是:

THR

当机器检查阈值计数器(通常是内存或缓存的 ECC 更正错误计数)超过可配置阈值时引发的中断。仅在某些系统上可用。

TRM

当 CPU 的温度阈值被超过时,会发生热事件中断。当温度恢复正常时,也可能会生成此中断。

SPU

伪中断是指某些 IO 设备在 APIC 完全处理之前引发然后降低的中断。因此,APIC 看到中断,但不知道它来自哪个设备。在这种情况下,APIC 将使用 0xff 的 IRQ 向量生成中断。这也可能是由芯片组错误引起的。

RES, CAL, TLB

重新调度、调用和 TLB 刷新中断会根据操作系统的需要从一个 CPU 发送到另一个 CPU。通常,内核开发人员和感兴趣的用户使用它们的统计信息来确定给定类型的中断的发生。

仅在相关时才显示上述 IRQ 向量。例如,阈值向量在 x86_64 平台上不存在。当系统是单处理器时,其他向量会被抑制。在撰写本文时,只有 i386 和 x86_64 平台支持新的 IRQ 向量显示。

在 2.4 中引入 /proc/irq 目录值得关注。它可用于将 IRQ 设置为 CPU 亲和性。这意味着您可以将一个 IRQ “挂钩”到仅一个 CPU,或排除一个 CPU 处理 IRQ。irq 子目录的内容是每个 IRQ 一个子目录,以及两个文件:default_smp_affinity 和 prof_cpu_mask。

例如:

> ls /proc/irq/
0  10  12  14  16  18  2  4  6  8  prof_cpu_mask
1  11  13  15  17  19  3  5  7  9  default_smp_affinity
> ls /proc/irq/0/
smp_affinity

smp_affinity 是一个位掩码,您可以在其中指定哪些 CPU 可以处理 IRQ。您可以通过执行以下操作来设置它:

> echo 1 > /proc/irq/10/smp_affinity

这意味着只有第一个 CPU 将处理 IRQ,但您也可以 echo 5,这意味着只有第一个和第三个 CPU 可以处理 IRQ。

默认情况下,每个 smp_affinity 文件的内容都相同:

> cat /proc/irq/0/smp_affinity
ffffffff

还有一个替代接口 smp_affinity_list,它允许指定 CPU 范围而不是位掩码

> cat /proc/irq/0/smp_affinity_list
1024-1031

default_smp_affinity 掩码适用于所有非活动 IRQ,这些 IRQ 是尚未分配/激活的 IRQ,因此缺少 /proc/irq/[0-9]* 目录。

SMP 系统上的 node 文件显示使用 IRQ 的设备将其自身报告为附加到的节点。此硬件局部性信息不包括有关任何可能的驱动程序局部性偏好的信息。

prof_cpu_mask 指定要由系统范围的分析器分析的 CPU。默认值为 ffffffff(如果只有 32 个 CPU,则为所有 CPU)。

IRQ 的路由方式由 IO-APIC 处理,并且在所有允许处理它的 CPU 之间进行轮循。与往常一样,内核比您拥有更多的信息,并且比您做得更好,因此默认设置对于几乎所有人来说都是最佳选择。[注意,这仅适用于那些支持“轮循”中断分配的 IO-APIC。]

在 /proc 中还有三个更重要的子目录:net、scsi 和 sys。一般规则是这些目录的内容,甚至它们的存在,都取决于您的内核配置。如果未启用 SCSI,则 scsi 目录可能不存在。net 也一样,只有在正在运行的内核中存在网络支持时才存在。

slabinfo 文件提供了关于 slab 级别内存使用情况的信息。Linux 在 2.2 版本中,在页面级别之上使用 slab 池进行内存管理。常用的对象都有自己的 slab 池(例如网络缓冲区、目录缓存等等)。

> cat /proc/buddyinfo

Node 0, zone      DMA      0      4      5      4      4      3 ...
Node 0, zone   Normal      1      0      0      1    101      8 ...
Node 0, zone  HighMem      2      0      0      1      1      0 ...

在某些工作负载下,外部碎片是一个问题,而 buddyinfo 是一个有用的工具,可以帮助诊断这些问题。buddyinfo 会提示你可以安全分配多大的区域,或者为什么之前的分配失败。

每一列代表特定阶数的可用页面数。在这个例子中,ZONE_DMA 中有 0 个 2^0*PAGE_SIZE 大小的块可用,ZONE_DMA 中有 4 个 2^1*PAGE_SIZE 大小的块可用,ZONE_NORMAL 中有 101 个 2^4*PAGE_SIZE 大小的块可用,等等...

更多关于外部碎片的信息可以在 pagetypeinfo 中找到。

> cat /proc/pagetypeinfo
Page block order: 9
Pages per block:  512

Free pages count per migrate type at order       0      1      2      3      4      5      6      7      8      9     10
Node    0, zone      DMA, type    Unmovable      0      0      0      1      1      1      1      1      1      1      0
Node    0, zone      DMA, type  Reclaimable      0      0      0      0      0      0      0      0      0      0      0
Node    0, zone      DMA, type      Movable      1      1      2      1      2      1      1      0      1      0      2
Node    0, zone      DMA, type      Reserve      0      0      0      0      0      0      0      0      0      1      0
Node    0, zone      DMA, type      Isolate      0      0      0      0      0      0      0      0      0      0      0
Node    0, zone    DMA32, type    Unmovable    103     54     77      1      1      1     11      8      7      1      9
Node    0, zone    DMA32, type  Reclaimable      0      0      2      1      0      0      0      0      1      0      0
Node    0, zone    DMA32, type      Movable    169    152    113     91     77     54     39     13      6      1    452
Node    0, zone    DMA32, type      Reserve      1      2      2      2      2      0      1      1      1      1      0
Node    0, zone    DMA32, type      Isolate      0      0      0      0      0      0      0      0      0      0      0

Number of blocks type     Unmovable  Reclaimable      Movable      Reserve      Isolate
Node 0, zone      DMA            2            0            5            1            0
Node 0, zone    DMA32           41            6          967            2            0

内核中的碎片避免机制通过将不同迁移类型的页面分组到称为页面块的相同连续内存区域中来实现。页面块的大小通常是默认的大页大小,例如在 X86-64 上为 2MB。通过根据页面的移动能力将页面分组,内核可以回收页面块内的页面,以满足高阶分配。

pagetypinfo 首先提供有关页面块大小的信息。然后,它提供与 buddyinfo 相同类型的信息,但按迁移类型细分,最后详细说明每种类型的页面块存在多少个。

如果 min_free_kbytes 已正确调整(libhugetlbfs 的 hugeadm 提出的建议 https://github.com/libhugetlbfs/libhugetlbfs/),则可以估计在给定时间点可以分配的大页数量。除非内存已被 mlock() 锁定,否则所有“可移动”块都应可分配。一些“可回收”块也应可分配,尽管可能需要回收大量文件系统元数据才能实现此目的。

allocinfo

提供有关代码库中所有位置的内存分配的信息。代码中的每个分配都通过其源文件、行号、模块(如果源自可加载模块)和调用分配的函数来标识。报告每个位置分配的字节数和调用次数。第一行指示文件版本,第二行是列出文件中字段的标题。

示例输出。

 > tail -n +3 /proc/allocinfo | sort -rn
127664128    31168 mm/page_ext.c:270 func:alloc_page_ext
 56373248     4737 mm/slub.c:2259 func:alloc_slab_page
 14880768     3633 mm/readahead.c:247 func:page_cache_ra_unbounded
 14417920     3520 mm/mm_init.c:2530 func:alloc_large_system_hash
 13377536      234 block/blk-mq.c:3421 func:blk_mq_alloc_rqs
 11718656     2861 mm/filemap.c:1919 func:__filemap_get_folio
  9192960     2800 kernel/fork.c:307 func:alloc_thread_stack_node
  4206592        4 net/netfilter/nf_conntrack_core.c:2567 func:nf_ct_alloc_hashtable
  4136960     1010 drivers/staging/ctagmod/ctagmod.c:20 [ctagmod] func:ctagmod_start
  3940352      962 mm/memory.c:4214 func:alloc_anon_folio
  2894464    22613 fs/kernfs/dir.c:615 func:__kernfs_new_node
  ...

meminfo

提供有关内存分布和利用率的信息。这因体系结构和编译选项而异。这里报告的一些计数器重叠。非重叠计数器报告的内存可能与总体内存使用量不符,并且某些工作负载的差异可能很大。在许多情况下,还有其他方法可以使用特定于子系统的接口查找额外的内存,例如 /proc/net/sockstat 用于 TCP 内存分配。

示例输出。您可能没有所有这些字段。

> cat /proc/meminfo

MemTotal:       32858820 kB
MemFree:        21001236 kB
MemAvailable:   27214312 kB
Buffers:          581092 kB
Cached:          5587612 kB
SwapCached:            0 kB
Active:          3237152 kB
Inactive:        7586256 kB
Active(anon):      94064 kB
Inactive(anon):  4570616 kB
Active(file):    3143088 kB
Inactive(file):  3015640 kB
Unevictable:           0 kB
Mlocked:               0 kB
SwapTotal:             0 kB
SwapFree:              0 kB
Zswap:              1904 kB
Zswapped:           7792 kB
Dirty:                12 kB
Writeback:             0 kB
AnonPages:       4654780 kB
Mapped:           266244 kB
Shmem:              9976 kB
KReclaimable:     517708 kB
Slab:             660044 kB
SReclaimable:     517708 kB
SUnreclaim:       142336 kB
KernelStack:       11168 kB
PageTables:        20540 kB
SecPageTables:         0 kB
NFS_Unstable:          0 kB
Bounce:                0 kB
WritebackTmp:          0 kB
CommitLimit:    16429408 kB
Committed_AS:    7715148 kB
VmallocTotal:   34359738367 kB
VmallocUsed:       40444 kB
VmallocChunk:          0 kB
Percpu:            29312 kB
EarlyMemtestBad:       0 kB
HardwareCorrupted:     0 kB
AnonHugePages:   4149248 kB
ShmemHugePages:        0 kB
ShmemPmdMapped:        0 kB
FileHugePages:         0 kB
FilePmdMapped:         0 kB
CmaTotal:              0 kB
CmaFree:               0 kB
HugePages_Total:       0
HugePages_Free:        0
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:               0 kB
DirectMap4k:      401152 kB
DirectMap2M:    10008576 kB
DirectMap1G:    24117248 kB
MemTotal

总可用 RAM(即物理 RAM 减去一些保留位和内核二进制代码)

MemFree

总可用 RAM。在高内存系统上,是 LowFree+HighFree 的总和

MemAvailable

估计在不使用交换的情况下,可用于启动新应用程序的内存量。根据 MemFree、SReclaimable、文件 LRU 列表的大小以及每个区域的低水位线计算得出。该估计考虑了系统需要一些页面缓存才能良好运行,并且并非所有可回收的 slab 都可回收,因为某些项目正在使用中。这些因素的影响因系统而异。

Buffers

用于原始磁盘块的相对临时存储,不应变得非常大(20MB 左右)

Cached

从磁盘读取的文件(页面缓存)以及 tmpfs 和 shmem 的内存缓存。不包括 SwapCached。

SwapCached

曾经被换出的内存,被换入但仍然在交换文件中(如果需要内存,则无需再次换出,因为它已经在交换文件中。这样可以节省 I/O)

Active

最近使用过的内存,除非绝对必要,否则通常不会回收。

Inactive

最近较少使用的内存。它更有资格被回收用于其他目的

Unevictable

为用户空间分配的无法回收的内存,例如 mlocked 页面、ramfs 支持页面、秘密 memfd 页面等。

Mlocked

使用 mlock() 锁定的内存。

HighTotal, HighFree

高内存是大约 860MB 物理内存以上的所有内存。高内存区域供用户空间程序或页面缓存使用。内核必须使用技巧来访问此内存,使其访问速度比低内存慢。

LowTotal, LowFree

低内存是可以用于高内存可以用于的所有用途的内存,但它也可供内核用于其自身的数据结构。除其他事项外,Slab 中的所有内容都分配在这里。当您耗尽低内存时,会发生糟糕的事情。

SwapTotal

可用交换空间的总量

SwapFree

从 RAM 中逐出的,临时存储在磁盘上的内存

Zswap

zswap 后端消耗的内存(压缩大小)

Zswapped

存储在 zswap 中的匿名内存量(原始大小)

Dirty

等待写回磁盘的内存

Writeback

正在积极写回磁盘的内存

AnonPages

映射到用户空间页表的非文件支持页面

Mapped

已 mmap 的文件,例如库

Shmem

共享内存 (shmem) 和 tmpfs 使用的总内存

KReclaimable

内核将在内存压力下尝试回收的内核分配。包括 SReclaimable(如下)和其他带有收缩器的直接分配。

Slab

内核数据结构缓存

SReclaimable

Slab 的一部分,可能会被回收,例如缓存

SUnreclaim

Slab 的一部分,在内存压力下无法回收

KernelStack

所有任务的内核堆栈消耗的内存

PageTables

用户空间页表消耗的内存

SecPageTables

二级页表消耗的内存,目前包括 x86 和 arm64 上的 KVM mmu 和 IOMMU 分配。

NFS_Unstable

始终为零。之前计算的已写入服务器但尚未提交到稳定存储的页面。

Bounce

用于块设备“bounce buffers”的内存

WritebackTmp

FUSE 用于临时写回缓冲区的内存

CommitLimit

根据 overcommit 比率 ('vm.overcommit_ratio'),这是当前系统上可分配的总内存量。仅当启用严格的 overcommit 记帐('vm.overcommit_memory' 中的模式 2)时,才会遵守此限制。

CommitLimit 的计算公式如下

CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
               overcommit_ratio / 100 + [total swap pages]

例如,在具有 1G 物理 RAM 和 7G 交换空间(vm.overcommit_ratio 为 30)的系统上,将产生 7.3G 的 CommitLimit。

有关更多详细信息,请参见 mm/overcommit-accounting 中的内存 overcommit 文档。

Committed_AS

系统上当前分配的内存量。已提交的内存是进程已分配的所有内存的总和,即使它们尚未“使用”这些内存。一个 malloc() 了 1G 内存但仅触及 300M 的进程将显示为使用 1G。此 1G 是 VM“承诺”的内存,可以随时由分配应用程序使用。如果系统上启用了严格的 overcommit('vm.overcommit_memory' 中的模式 2),则超出 CommitLimit(上面详细介绍)的分配将不被允许。如果需要保证进程一旦成功分配内存就不会因缺乏内存而失败,这将非常有用。

VmallocTotal

vmalloc 虚拟地址空间的总大小

VmallocUsed

已使用的 vmalloc 区域的量

VmallocChunk

vmalloc 区域中最大的连续空闲块

Percpu

分配给用于支持 percpu 分配的 percpu 分配器的内存。此统计信息不包括元数据的成本。

EarlyMemtestBad

RAM/内存中被早期 memtest 识别为损坏的 kB 量。如果未运行 memtest,则根本不会显示此字段。大小永远不会向下舍入为 0 kB。这意味着如果报告 0 kB,则可以安全地假设至少进行了一次 memtest,并且没有一次通过发现 RAM 的单个故障字节。

HardwareCorrupted

内核识别为损坏的 RAM/内存量(以 KB 为单位)。

AnonHugePages

映射到用户空间页表的非文件支持大页

ShmemHugePages

使用大页分配的共享内存 (shmem) 和 tmpfs 使用的内存

ShmemPmdMapped

使用大页映射到用户空间的共享内存

FileHugePages

用于使用大页分配的文件系统数据(页面缓存)的内存

FilePmdMapped

使用大页映射到用户空间的页面缓存

CmaTotal

为连续内存分配器 (CMA) 保留的内存

CmaFree

CMA 保留区中的剩余可用内存

HugePages_Total, HugePages_Free, HugePages_Rsvd, HugePages_Surp, Hugepagesize, Hugetlb

请参阅 HugeTLB 页面

DirectMap4k, DirectMap2M, DirectMap1G

内核 RAM 身份映射中使用的页表大小的细分

vmallocinfo

提供有关 vmalloced/vmaped 区域的信息。每个区域一行,包含区域的虚拟地址范围、以字节为单位的大小、创建者的调用者信息以及可选的信息,具体取决于区域的类型

pages=nr

页面数

phys=addr

如果指定了物理地址

ioremap

I/O 映射 (ioremap() 和 friends)

vmalloc

vmalloc() 区域

vmap

vmap()ed 页面

user

VM_USERMAP 区域

vpages

页面指针的缓冲区被 vmalloced(大区域)

N<node>=nr

(仅在 NUMA 内核上)在内存节点 <node> 上分配的页面数

> cat /proc/vmallocinfo
0xffffc20000000000-0xffffc20000201000 2101248 alloc_large_system_hash+0x204 ...
/0x2c0 pages=512 vmalloc N0=128 N1=128 N2=128 N3=128
0xffffc20000201000-0xffffc20000302000 1052672 alloc_large_system_hash+0x204 ...
/0x2c0 pages=256 vmalloc N0=64 N1=64 N2=64 N3=64
0xffffc20000302000-0xffffc20000304000    8192 acpi_tb_verify_table+0x21/0x4f...
phys=7fee8000 ioremap
0xffffc20000304000-0xffffc20000307000   12288 acpi_tb_verify_table+0x21/0x4f...
phys=7fee7000 ioremap
0xffffc2000031d000-0xffffc2000031f000    8192 init_vdso_vars+0x112/0x210
0xffffc2000031f000-0xffffc2000032b000   49152 cramfs_uncompress_init+0x2e ...
/0x80 pages=11 vmalloc N0=3 N1=3 N2=2 N3=3
0xffffc2000033a000-0xffffc2000033d000   12288 sys_swapon+0x640/0xac0      ...
pages=2 vmalloc N1=2
0xffffc20000347000-0xffffc2000034c000   20480 xt_alloc_table_info+0xfe ...
/0x130 [x_tables] pages=4 vmalloc N0=4
0xffffffffa0000000-0xffffffffa000f000   61440 sys_init_module+0xc27/0x1d00 ...
pages=14 vmalloc N2=14
0xffffffffa000f000-0xffffffffa0014000   20480 sys_init_module+0xc27/0x1d00 ...
pages=4 vmalloc N1=4
0xffffffffa0014000-0xffffffffa0017000   12288 sys_init_module+0xc27/0x1d00 ...
pages=2 vmalloc N1=2
0xffffffffa0017000-0xffffffffa0022000   45056 sys_init_module+0xc27/0x1d00 ...
pages=10 vmalloc N0=10

softirqs

提供自启动以来为每个 CPU 服务的软中断处理程序的计数。

> cat /proc/softirqs
              CPU0       CPU1       CPU2       CPU3
    HI:          0          0          0          0
TIMER:       27166      27120      27097      27034
NET_TX:          0          0          0         17
NET_RX:         42          0          0         39
BLOCK:           0          0        107       1121
TASKLET:         0          0          0        290
SCHED:       27035      26983      26971      26746
HRTIMER:         0          0          0          0
    RCU:      1678       1769       2178       2250

1.3 /proc/net 中的网络信息

子目录 /proc/net 遵循通常的模式。表 1-8 显示如果您配置内核以支持 IPv6,您将获得的额外值。表 1-9 列出了文件及其含义。

表 1-8:/proc/net 中的 IPv6 信息

文件

内容

udp6

UDP 套接字 (IPv6)

tcp6

TCP 套接字 (IPv6)

raw6

原始设备统计信息 (IPv6)

igmp6

此主机加入的 IP 多播地址 (IPv6)

if_inet6

IPv6 接口地址列表

ipv6_route

IPv6 的内核路由表

rt6_stats

全局 IPv6 路由表统计信息

sockstat6

套接字统计信息 (IPv6)

snmp6

Snmp 数据 (IPv6)

表 1-9:/proc/net 中的网络信息

文件

内容

arp

内核 ARP 表

dev

带有统计信息的网络设备

dev_mcast

设备正在侦听的第 2 层多播组(接口索引、标签、引用数、绑定地址数)。

dev_stat

网络设备状态

ip_fwchains

防火墙链链接

ip_fwnames

防火墙链名称

ip_masq

包含伪装表的目录

ip_masquerade

主要的伪装表

netstat

网络统计信息

raw

原始设备统计信息

route

内核路由表

rpc

包含 RPC 信息的目录

rt_cache

路由缓存

snmp

SNMP 数据

sockstat

套接字统计信息

softnet_stat

在线 CPU 的每个 CPU 的传入数据包队列统计信息

tcp

TCP 套接字

udp

UDP 套接字

unix

UNIX 域套接字

wireless

无线接口数据 (Wavelan 等)

igmp

此主机加入的 IP 多播地址

psched

全局数据包调度器参数。

netlink

PF_NETLINK 套接字列表

ip_mr_vifs

多播虚拟接口列表

ip_mr_cache

多播路由缓存列表

您可以使用此信息来查看系统中可用的网络设备以及在这些设备上路由的流量。

> cat /proc/net/dev
Inter-|Receive                                                   |[...
 face |bytes    packets errs drop fifo frame compressed multicast|[...
    lo:  908188   5596     0    0    0     0          0         0 [...
  ppp0:15475140  20721   410    0    0   410          0         0 [...
  eth0:  614530   7085     0    0    0     0          0         1 [...

...] Transmit
...] bytes    packets errs drop fifo colls carrier compressed
...]  908188     5596    0    0    0     0       0          0
...] 1375103    17405    0    0    0     0       0          0
...] 1703981     5535    0    0    0     3       0          0

此外,每个通道绑定接口都有自己的目录。例如,bond0 设备将有一个名为 /proc/net/bond0/ 的目录。它将包含特定于该绑定的信息,例如绑定的当前从属设备、从属设备的链接状态以及从属设备链接失败的次数。

1.4 SCSI 信息

如果您的系统中有一个 SCSI 或 ATA 主机适配器,您将在 /proc/scsi 中找到一个以该适配器的驱动程序命名的子目录。您还将在 /proc/scsi 中看到所有已识别的 SCSI 设备列表。

>cat /proc/scsi/scsi
Attached devices:
Host: scsi0 Channel: 00 Id: 00 Lun: 00
  Vendor: IBM      Model: DGHS09U          Rev: 03E0
  Type:   Direct-Access                    ANSI SCSI revision: 03
Host: scsi0 Channel: 00 Id: 06 Lun: 00
  Vendor: PIONEER  Model: CD-ROM DR-U06S   Rev: 1.04
  Type:   CD-ROM                           ANSI SCSI revision: 02

以驱动程序命名的目录为系统中找到的每个适配器包含一个文件。这些文件包含有关控制器的信息,包括使用的 IRQ 和 IO 地址范围。显示的信息量取决于您使用的适配器。该示例显示了 Adaptec AHA-2940 SCSI 适配器的输出。

> cat /proc/scsi/aic7xxx/0

Adaptec AIC7xxx driver version: 5.1.19/3.2.4
Compile Options:
  TCQ Enabled By Default : Disabled
  AIC7XXX_PROC_STATS     : Disabled
  AIC7XXX_RESET_DELAY    : 5
Adapter Configuration:
           SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter
                           Ultra Wide Controller
    PCI MMAPed I/O Base: 0xeb001000
 Adapter SEEPROM Config: SEEPROM found and used.
      Adaptec SCSI BIOS: Enabled
                    IRQ: 10
                   SCBs: Active 0, Max Active 2,
                         Allocated 15, HW 16, Page 255
             Interrupts: 160328
      BIOS Control Word: 0x18b6
   Adapter Control Word: 0x005b
   Extended Translation: Enabled
Disconnect Enable Flags: 0xffff
     Ultra Enable Flags: 0x0001
 Tag Queue Enable Flags: 0x0000
Ordered Queue Tag Flags: 0x0000
Default Tag Queue Depth: 8
    Tagged Queue By Device array for aic7xxx host instance 0:
      {255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}
    Actual queue depth per device for aic7xxx host instance 0:
      {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
Statistics:
(scsi0:0:0:0)
  Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8
  Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0)
  Total transfers 160151 (74577 reads and 85574 writes)
(scsi0:0:6:0)
  Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15
  Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0)
  Total transfers 0 (0 reads and 0 writes)

1.5 /proc/parport 中的并行端口信息

/proc/parport 目录包含有关系统并行端口的信息。它为每个端口都有一个子目录,以端口号命名 (0,1,2,...)。

这些目录包含表 1-10 中显示的四个文件。

表 1-10:/proc/parport 中的文件

文件

内容

autoprobe

已获取的任何 IEEE-1284 设备 ID 信息。

devices

使用该端口的设备驱动程序列表。当前正在使用该端口的设备的名称旁边会出现一个 + 号(可能不会出现在任何一个名称旁边)。

hardware

并行端口的基地址、IRQ 线和 DMA 通道。

irq

parport 为该端口使用的 IRQ。它在一个单独的文件中,允许您通过写入一个新值(IRQ 号或 none)来更改它。

1.6 /proc/tty 中的 TTY 信息

有关可用和实际使用的 tty 的信息可以在目录 /proc/tty 中找到。您可以在此目录中找到驱动程序和线路规程的条目,如表 1-11 所示。

表 1-11:/proc/tty 中的文件

文件

内容

drivers

驱动程序及其使用情况的列表

ldiscs

已注册的线路规程

driver/serial

单个 tty 线路的使用统计信息和状态

要查看当前正在使用哪些 tty,您可以简单地查看文件 /proc/tty/drivers

> cat /proc/tty/drivers
pty_slave            /dev/pts      136   0-255 pty:slave
pty_master           /dev/ptm      128   0-255 pty:master
pty_slave            /dev/ttyp       3   0-255 pty:slave
pty_master           /dev/pty        2   0-255 pty:master
serial               /dev/cua        5   64-67 serial:callout
serial               /dev/ttyS       4   64-67 serial
/dev/tty0            /dev/tty0       4       0 system:vtmaster
/dev/ptmx            /dev/ptmx       5       2 system
/dev/console         /dev/console    5       1 system:console
/dev/tty             /dev/tty        5       0 system:/dev/tty
unknown              /dev/tty        4    1-63 console

1.7 /proc/stat 中的杂项内核统计信息

有关内核活动的各种信息可在 /proc/stat 文件中找到。此文件中报告的所有数字都是自系统首次启动以来的总和。要快速查看,只需 cat 该文件

> cat /proc/stat
cpu  237902850 368826709 106375398 1873517540 1135548 0 14507935 0 0 0
cpu0 60045249 91891769 26331539 468411416 495718 0 5739640 0 0 0
cpu1 59746288 91759249 26609887 468860630 312281 0 4384817 0 0 0
cpu2 59489247 92985423 26904446 467808813 171668 0 2268998 0 0 0
cpu3 58622065 92190267 26529524 468436680 155879 0 2114478 0 0 0
intr 8688370575 8 3373 0 0 0 0 0 0 1 40791 0 0 353317 0 0 0 0 224789828 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 190974333 41958554 123983334 43 0 224593 0 0 0 <more 0's deleted>
ctxt 22848221062
btime 1605316999
processes 746787147
procs_running 2
procs_blocked 0
softirq 12121874454 100099120 3938138295 127375644 2795979 187870761 0 173808342 3072582055 52608 224184354

第一个“cpu”行汇总了所有其他“cpuN”行中的数字。这些数字标识 CPU 花费在执行不同类型工作上的时间。时间单位为 USER_HZ(通常为百分之一秒)。各列的含义如下,从左到右

  • user:在用户模式下执行的普通进程

  • nice:在用户模式下执行的已调整优先级的进程

  • system:在内核模式下执行的进程

  • idle:闲置

  • iowait:简而言之,iowait 表示等待 I/O 完成。但是存在一些问题

    1. CPU 不会等待 I/O 完成,iowait 是任务等待 I/O 完成的时间。当 CPU 由于未完成的任务 I/O 而进入空闲状态时,将在该 CPU 上调度另一个任务。

    2. 在多核 CPU 中,等待 I/O 完成的任务不会在任何 CPU 上运行,因此很难计算每个 CPU 的 iowait。

    3. /proc/stat 中的 iowait 字段的值在某些条件下会减少。

    因此,从 /proc/stat 读取的 iowait 不可靠。

  • irq:处理中断

  • softirq:处理软中断

  • steal:非自愿等待

  • guest:运行正常的访客

  • guest_nice:运行已调整优先级的访客

“intr”行给出了自启动以来处理的中断计数,针对每个可能的系统中断。第一列是所有已处理中断的总数,包括未编号的特定于架构的中断;每个后续列是该特定编号的中断的总数。未编号的中断不显示,仅汇总到总数中。

“ctxt”行给出跨所有 CPU 的上下文切换总数。

“btime”行给出系统启动的时间,以自 Unix 纪元以来的秒为单位。

“processes”行给出创建的进程和线程数,其中包括(但不限于)通过调用 fork() 和 clone() 系统调用创建的进程和线程。

“procs_running”行给出正在运行或准备运行的线程总数(即,可运行线程的总数)。

“procs_blocked”行给出当前被阻塞的进程数,等待 I/O 完成。

“softirq”行给出自启动以来处理的软中断计数,针对每个可能的系统软中断。第一列是所有已处理的软中断的总数;每个后续列是该特定软中断的总数。

1.8 Ext4 文件系统参数

有关已挂载的 ext4 文件系统的信息可以在 /proc/fs/ext4 中找到。每个已挂载的文件系统在 /proc/fs/ext4 中都有一个基于其设备名称的目录(即,/proc/fs/ext4/hdc 或 /proc/fs/ext4/sda9 或 /proc/fs/ext4/dm-0)。每个设备目录中的文件如下表 1-12 所示。

表 1-12:/proc/fs/ext4/<devname> 中的文件

文件

内容

mb_groups

多块分配器空闲块伙伴缓存的详细信息

1.9 /proc/consoles

显示已注册的系统控制台行。

要查看当前用于系统控制台 /dev/console 的字符设备行,您可以简单地查看文件 /proc/consoles

> cat /proc/consoles
tty0                 -WU (ECp)       4:7
ttyS0                -W- (Ep)        4:64

各列是

device

设备的名称

operations

  • R = 可以执行读取操作

  • W = 可以执行写入操作

  • U = 可以执行取消空白操作

flags

  • E = 已启用

  • C = 它是首选控制台

  • B = 它是主引导控制台

  • p = 它用于 printk 缓冲区

  • b = 它不是 TTY,而是盲文设备

  • a = 当 CPU 离线时,可以安全使用

major:minor

设备的 major 和 minor 号,用冒号分隔

摘要

/proc 文件系统提供有关正在运行的系统的信息。它不仅允许访问进程数据,还允许您通过读取层次结构中的文件来请求内核状态。

/proc 的目录结构反映了信息的类型,并且即使不是显而易见,也使查找特定数据变得容易。

第 2 章:修改系统参数

本章内容

  • 通过写入 /proc/sys 中的文件来修改内核参数

  • 探索修改某些参数的文件

  • 回顾 /proc/sys 文件树


/proc 中一个非常有趣的部分是目录 /proc/sys。这不仅是信息的来源,还允许您更改内核中的参数。尝试执行此操作时要非常小心。您可以优化您的系统,但也可能导致系统崩溃。永远不要在生产系统上更改内核参数。设置一个开发机器并进行测试,以确保一切按您想要的方式工作。一旦发生错误,您可能别无选择,只能重新启动计算机。

要更改值,只需将新值 echo 到文件中即可。您需要是 root 用户才能执行此操作。您可以创建自己的启动脚本,以便在每次系统启动时执行此操作。

/proc/sys 中的文件可用于微调和监控 Linux 内核运行中的杂项和常规事项。由于某些文件可能会无意中中断您的系统,因此在实际进行调整之前,最好阅读文档和源代码。在任何情况下,写入这些文件时都要非常小心。/proc 中的条目在 2.1.* 和 2.2 内核之间可能略有不同,因此如果有任何疑问,请查看 linux/Documentation 目录中的内核文档。本章主要基于 2.2 之前的内核中包含的文档,并在 Linux 内核的 2.2.1 版本中成为其中的一部分。

请参阅:Documentation/admin-guide/sysctl/ 目录以获取这些条目的描述。

摘要

内核行为的某些方面可以在运行时修改,而无需重新编译内核,甚至无需重新启动系统。/proc/sys 树中的文件不仅可以读取,还可以修改。您可以使用 echo 命令将值写入这些文件,从而更改内核的默认设置。

第 3 章:每个进程的参数

3.1 /proc/<pid>/oom_adj & /proc/<pid>/oom_score_adj- 调整 oom-killer 分数

这些文件可用于调整内存不足(OOM)条件下选择要终止的进程的糟糕程度启发式算法。

糟糕程度启发式算法会为每个候选任务分配一个值,范围从 0(永不终止)到 1000(始终终止),以确定目标进程。这些单位大致是进程基于对其当前内存和交换使用的估计,可能从允许的内存范围中分配的比例。例如,如果一个任务正在使用所有允许的内存,则其糟糕程度得分将为 1000。如果它正在使用允许内存的一半,则其得分将为 500。

“允许”内存量取决于调用 OOM 杀手时的上下文。如果是因为分配任务的 cpuset 分配的内存耗尽,则允许的内存表示分配给该 cpuset 的内存集合。如果是由于内存策略的节点耗尽,则允许的内存表示内存策略节点集合。如果是由于达到内存限制(或交换限制),则允许的内存是配置的限制。最后,如果是由于整个系统内存不足,则允许的内存表示所有可分配的资源。

在确定要终止哪个任务之前,/proc/<pid>/oom_score_adj 的值会添加到糟糕程度得分中。可接受的值范围从 -1000 (OOM_SCORE_ADJ_MIN) 到 +1000 (OOM_SCORE_ADJ_MAX)。这允许用户空间通过始终偏爱某个任务或完全禁用它来使 OOM 终止偏好两极分化。可能的最低值 -1000 等同于完全禁用该任务的 OOM 终止,因为它始终会报告糟糕程度得分为 0。

因此,用户空间可以非常简单地定义要考虑的每个任务的内存量。例如,设置 /proc/<pid>/oom_score_adj 值为 +500 大致相当于允许共享同一系统、cpuset、内存策略或内存控制器资源的其余任务至少多使用 50% 的内存。另一方面,值 -500 大致相当于将任务允许的内存的 50% 从针对该任务的评分中排除。

为了向后兼容以前的内核,也可以使用 /proc/<pid>/oom_adj 来调整糟糕程度得分。其可接受的值范围从 -16 (OOM_ADJUST_MIN) 到 +15 (OOM_ADJUST_MAX),以及用于完全禁用该任务的 OOM 终止的特殊值 -17 (OOM_DISABLE)。其值与 /proc/<pid>/oom_score_adj 线性缩放。

/proc/<pid>/oom_score_adj 的值不能降低到具有 CAP_SYS_RESOURCE 权限的进程设置的最后一个值之下。要将值降低到更低的值需要 CAP_SYS_RESOURCE 权限。

3.2 /proc/<pid>/oom_score - 显示当前的 OOM 杀手得分

此文件可用于检查任何给定 <pid> 的 OOM 杀手使用的当前得分。将其与 /proc/<pid>/oom_score_adj 一起使用,以调整在内存不足情况下应终止哪个进程。

请注意,导出的值包括 oom_score_adj,因此其有效范围为 [0,2000]。

3.3 /proc/<pid>/io - 显示 IO 统计字段

此文件包含每个正在运行的进程的 IO 统计信息。

示例

test:/tmp # dd if=/dev/zero of=/tmp/test.dat &
[1] 3828

test:/tmp # cat /proc/3828/io
rchar: 323934931
wchar: 323929600
syscr: 632687
syscw: 632675
read_bytes: 0
write_bytes: 323932160
cancelled_write_bytes: 0

描述

rchar

I/O 计数器:读取的字符数。此任务导致从存储读取的字节数。这只是此进程传递给 read() 和 pread() 的字节总和。它包括诸如 tty IO 之类的内容,并且不受是否需要实际的物理磁盘 IO 的影响(读取可能已从页面缓存中满足)。

wchar

I/O 计数器:写入的字符数。此任务导致或将导致写入磁盘的字节数。这里与 rchar 适用类似的注意事项。

syscr

I/O 计数器:读取系统调用。尝试计算读取 I/O 操作的数量,即诸如 read() 和 pread() 之类的系统调用。

syscw

I/O 计数器:写入系统调用。尝试计算写入 I/O 操作的数量,即诸如 write() 和 pwrite() 之类的系统调用。

read_bytes

I/O 计数器:读取的字节数。尝试计算此进程确实导致从存储层获取的字节数。在 submit_bio() 级别完成,因此对于块支持的文件系统是准确的。<请稍后添加有关 NFS 和 CIFS 的状态>

write_bytes

I/O 计数器:写入的字节数。尝试计算此进程导致发送到存储层的字节数。这是在页面变脏时完成的。

cancelled_write_bytes

这里最大的不准确之处是截断。如果一个进程向文件写入 1MB,然后删除该文件,则实际上不会执行任何写出操作。但是,它将被计算为导致写入 1MB。换句话说:此进程通过截断页面缓存导致没有发生的字节数。一个任务也可能导致“负”IO。如果此任务截断某些脏页面缓存,则另一个任务已被计算在内(在其 write_bytes 中)的一些 IO 将不会发生。我们可以直接从截断任务的 write_bytes 中减去它,但这样做会导致信息丢失。

注意

在其当前实现状态下,在 32 位计算机上,这有点竞争:如果进程 A 读取进程 B 的 /proc/pid/io,而进程 B 正在更新其中一个 64 位计数器,则进程 A 可能会看到一个中间结果。

有关此内容的更多信息,请参阅 Documentation/accounting 中的 taskstats 文档。

3.4 /proc/<pid>/coredump_filter - 核心转储过滤设置

当转储进程时,只要核心文件的大小没有限制,所有匿名内存都会写入核心文件。但是有时我们不想转储某些内存段,例如,巨大的共享内存或 DAX。相反,有时我们希望将文件支持的内存段保存到核心文件中,而不仅仅是单个文件。

/proc/<pid>/coredump_filter 允许您自定义在转储 <pid> 进程时将转储哪些内存段。coredump_filter 是内存类型的位掩码。如果设置了位掩码的位,则会转储相应内存类型的内存段,否则不会转储。

支持以下 9 种内存类型

  • (位 0)匿名私有内存

  • (位 1)匿名共享内存

  • (位 2)文件支持的私有内存

  • (位 3)文件支持的共享内存

  • (位 4)文件支持的私有内存区域中的 ELF 标头页(仅当清除位 2 时才有效)

  • (位 5)hugetlb 私有内存

  • (位 6)hugetlb 共享内存

  • (位 7)DAX 私有内存

  • (位 8)DAX 共享内存

请注意,诸如帧缓冲区的 MMIO 页面永远不会转储,而 vDSO 页面始终转储,无论位掩码状态如何。

请注意,位 0-4 不会影响 hugetlb 或 DAX 内存。hugetlb 内存仅受位 5-6 的影响,而 DAX 仅受位 7-8 的影响。

coredump_filter 的默认值为 0x33;这意味着所有匿名内存段、ELF 标头页和 hugetlb 私有内存都会被转储。

如果您不想转储附加到 pid 1234 的所有共享内存段,请将 0x31 写入进程的 proc 文件

$ echo 0x31 > /proc/1234/coredump_filter

创建新进程时,该进程会从其父进程继承位掩码状态。在程序运行之前设置 coredump_filter 非常有用。例如

$ echo 0x7 > /proc/self/coredump_filter
$ ./some_program

3.5 /proc/<pid>/mountinfo - 有关挂载的信息

此文件包含以下形式的行

36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
(1)(2)(3)   (4)   (5)      (6)     (n…m) (m+1)(m+2) (m+3)         (m+4)

(1)   mount ID:        unique identifier of the mount (may be reused after umount)
(2)   parent ID:       ID of parent (or of self for the top of the mount tree)
(3)   major:minor:     value of st_dev for files on filesystem
(4)   root:            root of the mount within the filesystem
(5)   mount point:     mount point relative to the process's root
(6)   mount options:   per mount options
(n…m) optional fields: zero or more fields of the form "tag[:value]"
(m+1) separator:       marks the end of the optional fields
(m+2) filesystem type: name of filesystem of the form "type[.subtype]"
(m+3) mount source:    filesystem specific information or "none"
(m+4) super options:   per super block options

解析器应忽略所有无法识别的可选字段。目前,可能的可选字段是

shared:X

挂载在对等组 X 中共享

master:X

挂载是对等组 X 的从属

propagate_from:X

挂载是从属,并接收来自对等组 X 的传播 [1]

unbindable

挂载是不可绑定的

有关挂载传播的更多信息,请参阅

3.6 /proc/<pid>/comm & /proc/<pid>/task/<tid>/comm

这些文件提供了一种访问任务的 comm 值的方法。它还允许任务设置其自身或其线程同级的 comm 值。与 cmdline 值相比,comm 值的大小有限,因此写入任何超过内核 TASK_COMM_LEN(当前为 16 个字符,包括 NUL 终止符)的值都将导致 comm 值被截断。

3.7 /proc/<pid>/task/<tid>/children - 有关任务子项的信息

此文件提供了一种快速检索由 <pid>/<tid> 对指向的任务的第一级子项 pid 的方法。该格式是以空格分隔的 pid 流。

请注意这里的“第一层”——如果一个子进程有自己的子进程,它们不会在这里列出;需要读取 /proc/<children-pid>/task/<tid>/children 才能获取后代进程。

由于此接口旨在快速且廉价,因此不保证提供精确的结果,并且可能会跳过某些子进程,尤其是在我们打印其 PID 后立即退出的子进程。因此,如果需要精确的结果,则需要停止或冻结正在检查的进程。

3.8 /proc/<pid>/fdinfo/<fd> - 有关已打开文件的信息

此文件提供与已打开文件关联的信息。常规文件至少有四个字段——“pos”、“flags”、“mnt_id”和“ino”。“pos”表示已打开文件当前的文件偏移量,以十进制形式表示[详情请参阅 lseek(2)];“flags”表示创建文件时使用的八进制 O_xxx 掩码[详情请参阅 open(2)];“mnt_id”表示包含已打开文件的文件系统的挂载 ID [详情请参阅 3.5 /proc/<pid>/mountinfo]。“ino”表示文件的 inode 号。

典型的输出是

pos:    0
flags:  0100002
mnt_id: 19
ino:    63107

与文件描述符关联的所有锁也显示在其 fdinfo 中

lock:       1: FLOCK  ADVISORY  WRITE 359 00:13:11691 0 EOF

诸如 eventfd、fsnotify、signalfd、epoll 等文件,除了常规的 pos/flags 对之外,还提供了特定于它们所代表的对象的信息。

Eventfd 文件

pos:    0
flags:  04002
mnt_id: 9
ino:    63107
eventfd-count:  5a

其中“eventfd-count”是计数器的十六进制值。

Signalfd 文件

pos:    0
flags:  04002
mnt_id: 9
ino:    63107
sigmask:        0000000000000200

其中“sigmask”是与文件关联的信号掩码的十六进制值。

Epoll 文件

pos:    0
flags:  02
mnt_id: 9
ino:    63107
tfd:        5 events:       1d data: ffffffffffffffff pos:0 ino:61af sdev:7

其中“tfd”是以十进制形式表示的目标文件描述符编号,“events”是正在监视的事件掩码,“data”是与目标关联的数据 [详情请参阅 epoll(7)]。

“pos”是目标文件的当前偏移量,以十进制形式表示[请参阅 lseek(2)],“ino”和“sdev”是目标文件所在的 inode 和设备号,均以十六进制格式表示。

Fsnotify 文件

对于 inotify 文件,格式如下

pos:    0
flags:  02000000
mnt_id: 9
ino:    63107
inotify wd:3 ino:9e7e sdev:800013 mask:800afce ignored_mask:0 fhandle-bytes:8 fhandle-type:1 f_handle:7e9e0000640d1b6d

其中,“wd”是以十进制形式表示的监视描述符,即目标文件描述符编号。“ino”和“sdev”是目标文件所在的 inode 和设备号,“mask”是事件掩码,全部以十六进制格式表示[详情请参阅 inotify(7)]。

如果内核在构建时启用了 exportfs 支持,则目标文件的路径将编码为文件句柄。文件句柄由三个字段“fhandle-bytes”、“fhandle-type”和“f_handle”提供,全部以十六进制格式表示。

如果内核在构建时未启用 exportfs 支持,则不会打印文件句柄。

如果尚未附加 inotify 标记,则将省略“inotify”行。

对于 fanotify 文件,格式为

pos:    0
flags:  02
mnt_id: 9
ino:    63107
fanotify flags:10 event-flags:0
fanotify mnt_id:12 mflags:40 mask:38 ignored_mask:40000003
fanotify ino:4f969 sdev:800013 mflags:0 mask:3b ignored_mask:40000000 fhandle-bytes:8 fhandle-type:1 f_handle:69f90400c275b5b4

其中 fanotify “flags” 和 “event-flags” 是在 fanotify_init 调用中使用的值,“mnt_id”是挂载点标识符,“mflags”是与标记关联的标志值,该值与事件掩码分开跟踪。“ino”和“sdev”是目标 inode 和设备,“mask”是事件掩码,“ignored_mask”是要忽略的事件掩码。所有这些都以十六进制格式表示。“mflags”、“mask”和“ignored_mask”的结合提供了有关 fanotify_mark 调用中使用的标志和掩码的信息 [详情请参阅 fsnotify 手册页]。

虽然前三行是强制性的并且总是打印的,但其余行是可选的,如果尚未创建任何标记,则可能会省略。

Timerfd 文件

pos:    0
flags:  02
mnt_id: 9
ino:    63107
clockid: 0
ticks: 0
settime flags: 01
it_value: (0, 49406829)
it_interval: (1, 0)

其中“clockid”是时钟类型,“ticks”是已发生的定时器过期次数[详情请参阅 timerfd_create(2)]。“settime flags”是以八进制形式表示的用于设置定时器的标志[详情请参阅 timerfd_settime(2)]。“it_value”是直到定时器过期为止的剩余时间。“it_interval”是定时器的间隔。请注意,定时器可以使用 TIMER_ABSTIME 选项设置,该选项将显示在“settime flags”中,但“it_value”仍然显示定时器的剩余时间。

DMA 缓冲区文件

pos:    0
flags:  04002
mnt_id: 9
ino:    63107
size:   32768
count:  2
exp_name:  system-heap

其中“size”是 DMA 缓冲区的大小,以字节为单位。“count”是 DMA 缓冲区文件的文件计数。“exp_name”是 DMA 缓冲区导出器的名称。

3.9 /proc/<pid>/map_files - 有关内存映射文件的信息

此目录包含表示进程正在维护的内存映射文件的符号链接。示例输出

| lr-------- 1 root root 64 Jan 27 11:24 333c600000-333c620000 -> /usr/lib64/ld-2.18.so
| lr-------- 1 root root 64 Jan 27 11:24 333c81f000-333c820000 -> /usr/lib64/ld-2.18.so
| lr-------- 1 root root 64 Jan 27 11:24 333c820000-333c821000 -> /usr/lib64/ld-2.18.so
| ...
| lr-------- 1 root root 64 Jan 27 11:24 35d0421000-35d0422000 -> /usr/lib64/libselinux.so.1
| lr-------- 1 root root 64 Jan 27 11:24 400000-41a000 -> /usr/bin/ls

链接的名称表示映射的虚拟内存边界,即 vm_area_struct::vm_start-vm_area_struct::vm_end。

map_files 的主要目的是以快速方式检索一组内存映射文件,而不是解析 /proc/<pid>/maps 或 /proc/<pid>/smaps,这两个文件都包含更多记录。同时,可以从两个进程的列表中 open(2) 映射,并比较它们的 inode 号以找出哪些匿名内存区域实际上是共享的。

3.10 /proc/<pid>/timerslack_ns - 任务 timerslack 值

此文件提供任务的 timerslack 值,以纳秒为单位。此值指定为了合并定时器并避免不必要的唤醒,正常定时器可以延迟的时间量。

这允许调整任务的交互性与功耗之间的权衡。

向该文件写入 0 会将任务的 timerslack 设置为默认值。

有效值为 0 - ULLONG_MAX

应用程序设置该值必须具有指定任务的 PTRACE_MODE_ATTACH_FSCREDS 级别权限才能更改其 timerslack_ns 值。

3.11 /proc/<pid>/patch_state - Livepatch 补丁操作状态

启用 CONFIG_LIVEPATCH 时,此文件显示任务的补丁状态值。

值“-1”表示没有补丁正在转换中。

值“0”表示补丁正在转换中,并且任务未打补丁。如果要启用补丁,则任务尚未打补丁。如果要禁用补丁,则任务已卸载补丁。

值“1”表示补丁正在转换中,并且任务已打补丁。如果要启用补丁,则任务已打补丁。如果要禁用补丁,则任务尚未卸载补丁。

3.12 /proc/<pid>/arch_status - 任务架构特定状态

启用 CONFIG_PROC_PID_ARCH_STATUS 时,此文件显示任务的架构特定状态。

示例

$ cat /proc/6753/arch_status
AVX512_elapsed_ms:      8

描述

x86 特定条目

AVX512_elapsed_ms

如果机器支持 AVX512,则此条目显示自上次记录 AVX512 使用情况以来经过的毫秒数。当任务被调度出时,会尽力进行记录。这意味着该值取决于两个因素

  1. 任务在 CPU 上花费的时间,而没有被调度出去。通过 CPU 隔离和单个可运行任务,这可能需要几秒钟。

  2. 自任务上次被调度出去以来的时间。根据被调度出去的原因(时间片用完、系统调用...),这可能是一个任意长的时间。

因此,该值不能被认为是精确和权威的信息。使用此信息的应用程序必须了解系统上的整体情况,以确定任务是否是真正的 AVX512 用户。可以使用性能计数器获得精确的信息。

特殊的“-1”值表示没有记录到 AVX512 使用情况,因此该任务不太可能是 AVX512 用户,但这取决于工作负载和调度场景,也可能是上面提到的假阴性。

第 4 章:配置 procfs

4.1 挂载选项

支持以下挂载选项

hidepid=

设置 /proc/<pid>/ 的访问模式。

gid=

设置授权了解进程信息的用户组。

subset=

仅显示 procfs 的指定子集。

hidepid=off 或 hidepid=0 表示经典模式 - 每个人都可以访问所有 /proc/<pid>/ 目录(默认)。

hidepid=noaccess 或 hidepid=1 表示用户可能无法访问任何 /proc/<pid>/ 目录,但他们自己的目录除外。诸如 cmdline、sched*、status 之类的敏感文件现在受到其他用户的保护。这使得无法了解任何用户是否运行特定的程序(假设该程序不会通过其行为自行暴露)。作为额外的奖励,由于其他用户无法访问 /proc/<pid>/cmdline,因此通过程序参数传递敏感信息的编写不良的程序现在受到本地窃听者的保护。

hidepid=invisible 或 hidepid=2 表示 hidepid=1,外加所有 /proc/<pid>/ 对其他用户完全不可见。这并不意味着它隐藏了具有特定 pid 值的进程是否存在的事实(可以通过其他方式获知,例如使用 “kill -0 $PID”),而是隐藏了进程的 uid 和 gid,否则可以通过 stat() /proc/<pid>/ 来获取。这大大增加了入侵者收集有关正在运行的进程的信息的难度,例如,某个守护进程是否以提升的权限运行,其他用户是否运行某些敏感程序,或者其他用户是否运行任何程序等。

hidepid=ptraceable 或 hidepid=4 表示 procfs 应该只包含调用者可以 ptrace 的 /proc/<pid>/ 目录。

gid= 定义了一个组,该组被授权可以获取被 hidepid= 禁止的进程信息。如果您使用一些需要了解进程信息的守护进程,例如 identd,只需将 identd 添加到此组即可。

subset=pid 隐藏 procfs 中所有与任务无关的顶级文件和目录。

第五章:文件系统行为

最初,在 pid 命名空间出现之前,procfs 是一个全局文件系统。这意味着系统中只有一个 procfs 实例。

当添加 pid 命名空间时,每个 pid 命名空间中都挂载了一个单独的 procfs 实例。因此,procfs 挂载选项在同一命名空间内的所有挂载点之间是全局的。

# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0

# strace -e mount mount -o hidepid=1 -t proc proc /tmp/proc
mount("proc", "/tmp/proc", "proc", 0, "hidepid=1") = 0
+++ exited with 0 +++

# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=2 0 0
proc /tmp/proc proc rw,relatime,hidepid=2 0 0

只有在重新挂载后,procfs 挂载选项才会更改所有挂载点。

# mount -o remount,hidepid=1 -t proc proc /tmp/proc

# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=1 0 0
proc /tmp/proc proc rw,relatime,hidepid=1 0 0

此行为与其他文件系统的行为不同。

新的 procfs 行为更像其他文件系统。每个 procfs 挂载都会创建一个新的 procfs 实例。挂载选项会影响自身的 procfs 实例。这意味着在同一个 pid 命名空间中,可以有多个 procfs 实例以不同的过滤选项显示任务。

# mount -o hidepid=invisible -t proc proc /proc
# mount -o hidepid=noaccess -t proc proc /tmp/proc
# grep ^proc /proc/mounts
proc /proc proc rw,relatime,hidepid=invisible 0 0
proc /tmp/proc proc rw,relatime,hidepid=noaccess 0 0