5-内核开发-/proc File System 学习
课程简介:
Linux内核开发入门是一门旨在帮助学习者从最基本的知识开始学习Linux内核开发的入门课程。该课程旨在为对Linux内核开发感兴趣的初学者提供一个扎实的基础,让他们能够理解和参与到Linux内核的开发过程中。
课程特点:
1. 入门级别:该课程专注于为初学者提供Linux内核开发的入门知识。无论你是否具有编程或操作系统的背景,该课程都将从最基本的概念和技术开始,逐步引导学习者深入了解Linux内核开发的核心原理。
2. 系统化学习:课程内容经过系统化的安排,涵盖了Linux内核的基础知识、内核模块编程、设备驱动程序开发等关键主题。学习者将逐步了解Linux内核的结构、功能和工作原理,并学习如何编写和调试内核模块和设备驱动程序。
3. 实践导向:该课程强调实践,通过丰富的实例和编程练习,帮助学习者将理论知识应用到实际的Linux内核开发中。学习者将有机会编写简单的内核模块和设备驱动程序,并通过实际的测试和调试来加深对Linux内核开发的理解。
4. 配套资源:为了帮助学习者更好地掌握课程内容,该课程提供了丰富的配套资源,包括教学文档、示例代码、实验指导和参考资料等。学习者可以根据自己的学习进度和需求,灵活地利用这些资源进行学习和实践。
无论你是计算机科学专业的学生、软件工程师还是对Linux内核开发感兴趣的爱好者,Linux内核开发入门课程都将为你提供一个扎实的学习平台,帮助你掌握Linux内核开发的基础知识,为进一步深入研究和应用Linux内核打下坚实的基础。
这一讲主要讲述如何/proc/ 文件系统
有时候,我们后端开发工程师经常会用各种命令去check Linux 服务器机器配置,例如命令:
cat /proc/cpuinfo ,cat /proc/meminfo 但是你想过他们的原理是怎么样的吗?今天讲的这个/proc 文件系统就与这个命令有关。让我们一起来浅显的了解下吧。(后面我们计划定义自己的基于 proc/原理的内核模块)
(1) 介绍
/proc 文件系统是一个伪文件系统,它提供有关正在运行的 Linux 内核的信息。它最初旨在允许轻松访问有关进程的信息(因此得名),但现在它被内核的每一小
部分使用,这些小部分有一些有趣的信息要报告。
(2) 常见文件
/proc 文件系统中的一些有用文件包括:
- /proc/cpuinfo:包含有关 CPU 的信息,例如型号、速度和缓存大小。
- /proc/meminfo:包含有关内存使用情况的统计信息,例如总内存量、已用内存量和空闲内存量。
- /proc/uptime:包含有关系统已运行时间的统计信息。
- /proc/loadavg:包含有关系统负载平均值的统计信息。
- /proc/diskstats:包含有关磁盘活动和 I/O 统计信息的统计信息。
- /proc/net/dev:包含有关网络设备和流量的统计信息。
- /proc/version:包含有关正在运行的内核的版本和编译信息。
此外 /proc 文件系统还可以用于控制某些内核功能。例如,您可以使用 /proc/sys/kernel/printk
文件来更改内核日志记录级别,这个printk 前几节课程中的代码中多次用到。
/proc 文件系统是一个额外的机制,内核和内核模块可以使用它向进程发送信息。
它最初设计为一种轻松访问有关进程信息的方法(例如进程列表、状态和资源使用情况)。
现在,内核中的每个组件都可以使用 /proc 文件系统来报告任何有趣的信息。
内核是操作系统的核心,负责管理硬件、内存和进程。内核模块是可加载到内核中的代码模块,用于添加
额外的功能(例如设备驱动程序或文件系统支持)。
/proc 文件系统为内核和内核模块提供了一种与进程通信的方法。进程可以读取 /proc 文件系统中
的文件以获取有关内核和系统的信息。
因此,/proc 文件系统是一个非常有用的工具,可用于监视系统、诊断问题和控制内核行为。
(3)实现
那么如何实现一个简单的/proc 下的模块呢?
首先
(a)需要实现定义
proc_ops proc_file_fops
proc_dir_entry *our_proc_file;
(a)模块初始化和清理函数:
procfs1_init():此函数在模块加载到内核时调用。它使用 proc_create() 函数创建 /proc/helloworld 文件。如果无法创建文件,该函数将打印错误消息并返回错误代码。
procfs1_exit():此函数在模块从内核卸载时调用。它使用 proc_remove() 函数删除 /proc/helloworld 文件。
(a)文件操作结构:
proc_file_fops:此结构定义了 /proc/helloworld 文件的文件操作。它包含一个条目 proc_read,该条目是处理来自用户空间程序的读取请求的函数。
(a)读取函数:
procfile_read():当用户空间程序从 /proc/helloworld 文件读取时调用此函数。它将字符串 "HelloWorld!\ " 复制到用户空间程序提供的缓冲区中。
全部代码如下:
hello.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 6, 0)
#define HAVE_PROC_OPS
#endif
#define procfs_name "helloworld"
static struct proc_dir_entry *our_proc_file;
static ssize_t procfile_read(struct file *file_pointer, char __user *buffer,
size_t buffer_length, loff_t *offset)
{
char s[13] = "HelloWorld!\n";
int len = sizeof(s);
ssize_t ret = len;
if (*offset >= len || copy_to_user(buffer, s, len)) {
pr_info("copy_to_user failed\n");
ret = 0;
} else {
pr_info("procfile read %s\n", file_pointer->f_path.dentry->d_name.name);
*offset += len;
}
return ret;
}
#ifdef HAVE_PROC_OPS
static const struct proc_ops proc_file_fops = {
.proc_read = procfile_read,
};
#else
static const struct file_operations proc_file_fops = {
.read = procfile_read,
};
#endif
static int __init procfs1_init(void)
{
our_proc_file = proc_create(procfs_name, 0644, NULL, &proc_file_fops);
if (NULL == our_proc_file) {
proc_remove(our_proc_file);
pr_alert("Error:Could not initialize /proc/%s\n", procfs_name);
return -ENOMEM;
}
pr_info("/proc/%s created\n", procfs_name);
return 0;
}
static void __exit procfs1_exit(void)
{
proc_remove(our_proc_file);
pr_info("/proc/%s removed\n", procfs_name);
}
module_init(procfs1_init);
module_exit(procfs1_exit);
MODULE_LICENSE("GPL");
Makefile
obj-m += hello.o
CFLAGS := -Wall -O2
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
在 /proc 文件系统下创建的模块可以利用工作交互机理来处理来自用户空间进程的请求。
/proc 文件系统是一个伪文件系统,它允许用户空间进程访问内核信息和控制内核行为。在 /proc 文件系统下创建的模块可以导出文件和目录,用户空间进程可以通过这些文件和目录与模块进行交互。
当用户空间进程访问模块导出的文件时,模块可以安排一个工作请求来处理请求。工作请求将被添加到一个工作队列中,并且工作队列线程将执行工作请求。
例如,一个在 /proc 文件系统下创建的模块可以导出一个文件,该文件允许用户空间进程读取内核中的某个数据结构。当用户空间进程读取该文件时,模块可以安排一个工作请求来获取数据结构并将其内容复制到一个缓冲区中。工作队列线程将执行工作请求,并将数据复制到缓冲区中。然后,用户空间进程可以从缓冲区中读取数据。
通过这种方式,/proc 文件系统下的模块可以利用工作交互机理来处理用户空间进程的请求,而无需阻塞调用进程。
运行效果:
peach@peach-VirtualBox:~/ProcModule$ make
make -C /lib/modules/5.15.0-105-generic/build M=/home/peach/ProcModule modules
make[1]: Entering directory '/usr/src/linux-headers-5.15.0-105-generic'
CC [M] /home/peach/ProcModule/hello.o
MODPOST /home/peach/ProcModule/Module.symvers
CC [M] /home/peach/ProcModule/hello.mod.o
LD [M] /home/peach/ProcModule/hello.ko
BTF [M] /home/peach/ProcModule/hello.ko
Skipping BTF generation for /home/peach/ProcModule/hello.ko due to unavailability of vmlinux
make[1]: Leaving directory '/usr/src/linux-headers-5.15.0-105-generic'
执行安装 insmod
然后验证:
(4)总结
总体而言,/proc 文件系统是一个非常有用的工具,可用于获取有关正在运行的 Linux 系统的信息和控制某些内核功能。
(5)参考
The Linux Kernel Module Programming Guide (sysprog21.github.io)