proc 文件系统,我觉得我的抽象思维有点不行,用户空间对这些值进行更改,代码是怎么体现的了 ?


一、proc 文件系统概述
proc 文件系统让查看和调整计算机内核设置变得更简单。它像一个特殊文件夹,里面存着内核的各种信息。用户可以直接用 cat(查看)或 echo(设置)命令,或者通过程序读写文件,就能获取或修改内核参数,而不用重新编译整个内核。
为什么 proc 文件系统重要?
以前:要查看或修改内核数据,必须写专门的程序深入内核内存操作,需要很高深的技术知识,还可能破坏系统稳定性。而且每次内核升级,程序可能需要重新编写。
现在:通过 proc 文件系统,程序只需像读写普通文件一样操作,就能安全地获取信息或调整参数。这不仅更简单安全,还能减少对内核版本变化的依赖。
通过 proc 文件系统,我们可以轻松获取以下信息:
对于特权程序(如系统工具):
系统现在有多少个程序在运行?
每个程序打开了哪些文件?
每个程序用了多少内存?历史上最高用了多少?
每个程序开了几个线程?每个线程现在在做什么?
系统启动后遇到过哪些类型的中断?发生了多少次?
对于普通程序(比如自己的应用程序):
自己开了哪些线程?每个线程状态如何?
各自用了多少内存?
程序加载的动态库被映射到内存的哪个地址?
简单来说: proc 文件系统像一个“控制面板”,把内核的数据整理成文件形式,让用户能用最基础的命令或代码直接操作,既安全又方便。
二、proc 文件系统详解
/proc 文件系统
/proc 是 Linux 系统的一个虚拟文件系统,主要用来查看系统运行时的信息。它最初设计用于显示进程(程序)的实时状态,比如进程在做什么、开了哪些文件或网络连接,后来也扩展了内核参数、硬件信息等内容。
/proc/cpuinfo
作用:显示 CPU 的详细参数。 例子:
$ cat /proc/cpuinfo
processor : 0 # CPU 核心编号(从0开始)
model name : Intel Core i5... # CPU 型号
cpu MHz : 2400 # 当前运行频率(单位:MHz)
cache size : 3072 KB # 三级缓存大小
address sizes: 42位物理地址,48位虚拟地址 # 支持的最大内存2
3
4
5
6
关键信息:
CPU 核心数、型号、频率、缓存大小
物理内存最大支持量(如 42 位=4TB 物理内存)
/proc/meminfo
作用:显示内存使用情况,比 top 更详细。 常见参数:
MemTotal:物理内存总量MemFree:空闲物理内存SwapTotal:交换分区(虚拟内存)总量SReclaimable:可回收的缓存内存KernelStack:内核栈占用内存
用处:
- 调试内存问题时,查看具体内存分配细节(如缓存、 slab 内存等)。
/proc/kallsyms
作用:列出内核函数和变量的地址。 用途:
- 内核开发者用来调试程序崩溃问题(如查看崩溃时的函数调用堆栈)。
/proc/kcore
作用:内核内存的完整映像文件。 用途:
- 用调试工具(如 gdb)直接分析运行中的内核状态,类似程序崩溃时的 core 文件。
/proc/interrupts
作用:统计各 CPU 核心处理的中断数量。 例子:
CPU0: 1234 # CPU0 处理的中断数
CPU1: 5678 # CPU1 处理的中断数2
关键点:
- 默认中断可能集中在 CPU0,需用
irqbalance工具分配到其他核心,提升多核性能。
/proc/loadavg
作用:显示系统负载(CPU 和任务队列的忙碌程度)。 例子:
$ cat /proc/loadavg
0.03 0.07 0.06 2/171 287002
前三项:1 分钟/5 分钟/15 分钟的平均负载。数值越小越轻松,超过 CPU 核心数表示任务排队。
第四项:运行中的任务数/总任务数(如 2/171 表示当前有 2 个任务在运行)。
第五项:占用资源最多的进程 ID。
/proc/PID/(每个进程的目录)
系统为每个进程创建一个以 PID(进程号)命名的目录,例如 /proc/1234/。 常用文件:
status:进程状态(内存使用、线程数等)。maps:进程的内存映射信息,显示程序加载的文件和内存区域。fd:进程打开的文件描述符(即当前打开的文件或网络连接)。
示例:**maps** 文件内容
$ cat /proc/1234/maps
00400000-0040b000 r-xp /usr/bin/cat # 程序本身的代码区域
7fe9d3f29000-7fe9d40eb000 r-xp /lib/libc.so # 加载的共享库
[heap] 00733000-00754000 rw-p # 堆内存区域2
3
4
每列含义:
内存地址范围(如
00400000-0040b000)。权限(
r=读,w=写,x=执行,p=可访问)。文件路径或特殊标记(如
[heap]表示堆内存)。
总结
这些文件是 Linux 的“系统体检表”,开发者和运维人员可以通过它们快速获取硬件状态、进程行为、内核运行等信息,用于调试、优化或故障排查。
三、procfs 主要接口
表格 还在加载中,请等待加载完成后再尝试复制
四、添加一个 procfs 文件实现例程
procfs 用来进行相关驱动信息的读取,还是建议使用 debugfs 来做调试功能。
要为
procfs创建接口,只需要调用proc_create接口。读/写处理函数依附在
struct file_operations结构体。卸载操作使用
remove_proc_entry
#include <linux/init.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
/*** 驱动信息 ***/
MODULE_LICENSE("Dual BSD/GPL");
#define DRIVER_NAME "MyDevice"
#define PROC_NAME "MyDevice_test"
/* procfs 测试变量 */
static char proc_test_string[16];
static int flag_read = 0;
/* /proc/MyDevice_test访问时调用的函数 */
static int mydevice_proc_open(struct inode *inode, struct file *file)
{
printk("mydevice_proc_open\n");
flag_read = 0;
return 0;
}
/* /proc/MyDevice_test read */
static ssize_t mydevice_proc_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
printk("mydevice_proc_read\n");
if (flag_read == 0) {
int len;
len = sprintf(buf, "%s\n", proc_test_string);
flag_read = 1;
return len;
} else {
return 0;
}
}
/* /proc/MyDevice_test write */
static ssize_t mydevice_proc_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
printk("mydevice_proc_write\n");
if (count > sizeof(proc_test_string)) count = sizeof(proc_test_string) - 1;
if (copy_from_user(proc_test_string, buf, count)) {
return -EFAULT;
}
proc_test_string[count] = '\0';
return count;
}
/* file_operations */
static struct file_operations mydevice_proc_fops = {
.owner = THIS_MODULE,
.open = mydevice_proc_open,
.read = mydevice_proc_read, //cat
.write = mydevice_proc_write, //echo
};
/* 加载 (insmod)时调用的函数 */
static int mydevice_init(void)
{
struct proc_dir_entry *entry;
printk("mydevice_init\n");
/* 创建 procfs */
entry = proc_create(interrupts, S_IRUGO | S_IWUGO, NULL, &mydevice_proc_fops);
if (entry == NULL) {
printk(KERN_ERR "proc_create\n");
return -ENOMEM;
}
return 0;
}
/* 卸载(rmmod)时调用的函数 */
static void mydevice_exit(void)
{
printk("mydevice_exit\n");
/* procfs 卸载く */
remove_proc_entry(PROC_NAME, NULL);
}
module_init(mydevice_init);
module_exit(mydevice_exit);2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
加载模块后,该 proc_create 函数会创建一个文件 /proc/MyDevice_test。S_IRUGO | S_IWUGO 与 0666 相同,为所有用户提供 RW 访问权限。
五、系统里面案例
drivers/rkflash/rkflash_blk.c

