下面是关于“Linux内核设备驱动之proc文件系统笔记整理”的完整攻略:
概述
proc文件系统是一个伪文件系统(虚拟文件系统),它存在于内存中,不占用硬盘空间。它允许内核把内部数据结构暴露给用户空间,并提供了一种简单的接口,以便用户空间程序与内核模块之间相互通信和传递信息。
本篇攻略对proc文件系统进行详细讲解,介绍proc文件系统的特性、常用文件操作、编写proc文件的方法以及示例代码等。
特性
- proc文件系统是一个伪文件系统(虚拟文件系统),不占用硬盘空间,存在于内存中。
- proc文件系统建立在内核中,是内核数据结构的一种映射,可以获得内核的各种数据信息。
- proc文件系统不要求提供存储器操作,无需磁盘空间即可存取当前系统运行的各种数据信息。
- proc文件系统不要求硬件支持,基本所有的Linux操作系统都支持proc文件系统。
常用文件操作
在proc文件系统中,常用的文件操作有:
- 读文件:将文件的内容读出来,可以通过cat等命令实现。
- 写文件:向文件写入数据,可以通过echo等命令实现。
- 打开文件:在应用程序中打开一个文件,是通过open()函数实现的。
- 关闭文件:关闭文件可以通过close()函数实现。
编写proc文件的方法
编写proc文件需要原理内核模块,使用proc接口来处理读/写等操作,并将其挂载到proc文件系统中。下面介绍一下编写proc文件的方法:
1. 创建结构体
首先需要定义一个包含读操作和写操作的结构体:
struct file_operations fop = {
.read = my_read,
.write = my_write
};
my_read
和my_write
是读写操作的函数地址,需要编写对应的读写函数实现。
2. 指定proc文件名
定义好file_operations
结构体之后,需要用proc_create
函数来注册proc文件。此函数原型为:
struct proc_dir_entry *proc_create(const char *name, mode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops);
其中,name
是proc文件的文件名,mode
是文件的权限,parent
是proc文件的父目录,proc_fops
是文件操作结构体。
3. 实现读函数
在file_operations
结构体中定义的读函数,实际上就是读取内核数据结构并将其以ASCII码的形式输出。读函数的原型如下:
ssize_t my_read(struct file *file, char __user *buf, size_t count, loff_t *ppos);
其中,file
是文件指针,用于访问文件的数据;buf
是用于存储文件数据的缓冲区;count
是要读取数据字节数;ppos
是文件偏移量。读函数需要返回成功读取的字节数。
4. 实现写函数(可选)
与读函数类似,写函数实现了将用户输入的数据解析并放入内核数据结构中的功能。写函数的原型如下:
ssize_t my_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos);
其中,file
是文件指针,用于访问文件的数据;buf
是包含写入数据的缓冲区;count
是要写入数据的字节数;ppos
是文件偏移量。写函数需要返回成功写入的字节数。
示例说明
为了更好地理解proc文件系统的用法和创建过程,以下提供两个示例。
示例1:实现读取系统级别内存信息的proc文件
此示例实现了一个proc文件用来读取系统级别的内存信息。具体实现步骤如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
#define PROC_MEMINFO "proc-test"
MODULE_AUTHOR("My Name");
MODULE_LICENSE("GPL");
static struct proc_dir_entry *meminfo_entry;
static int meminfo_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len;
// 读取系统内存信息,并将信息格式化
len = sprintf(page, "Total RAM: %lu\n", totalram_pages);
len += sprintf(page + len, "Free RAM : %lu\n", freeram_pages);
len += sprintf(page + len, "Shared RAM: %lu\n", totalcma_pages);
len += sprintf(page + len, "Number of processes : %d\n", nr_processes());
return len;
}
static int __init meminfo_init(void)
{
// 创建目录项
meminfo_entry = proc_create(PROC_MEMINFO, 0, NULL, &meminfo_file_ops);
if (meminfo_entry == NULL) {
printk(KERN_ERR "meminfo: Could not create proc entry\n");
return -ENOMEM;
}
printk(KERN_INFO "meminfo: Module loaded.\n");
return 0;
}
static void __exit meminfo_exit(void)
{
// 移除目录项
remove_proc_entry(PROC_MEMINFO, NULL);
printk(KERN_INFO "meminfo: Module unloaded.\n");
}
module_init(meminfo_init);
module_exit(meminfo_exit);
在该示例中创建了一个名为proc-test
的proc文件,读函数meminfo_read_proc
实现了读取系统内存信息的功能。这个函数会读取系统内存信息,并将信息格式化后放入page
缓冲区中。
示例2:实现简单的统计字符数和行数的proc文件
此示例实现了一个proc文件用来读取指定文件的字符数和行数。具体实现步骤如下:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#define PROC_MYFILE "proc-mycalc"
MODULE_AUTHOR("My Name");
MODULE_LICENSE("GPL");
static char my_str[100];
static struct proc_dir_entry *myfile_entry;
static int mycalc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data)
{
char tmp_str[100];
unsigned int length = 0;
unsigned int words = 0;
int i = 0;
mm_segment_t old_fs;
struct file *f;
// 打开指定的文件
f = filp_open(my_str, O_RDONLY, 0);
if (IS_ERR(f)) {
printk(KERN_ERR "mycalc: Could not open file %s\n", my_str);
return -1;
}
// 读取文件内容并计算字符数和行数
old_fs = get_fs();
set_fs(KERNEL_DS);
while (vfs_read(f, tmp_str, 100, &f->f_pos) > 0) {
for (i = 0; i < 100; i++) {
if (tmp_str[i] == '\n') {
words++;
} else {
length++;
}
}
}
set_fs(old_fs);
filp_close(f, NULL);
return sprintf(page, "Length: %u\nWords : %u\n", length, words);
}
static ssize_t mycalc_write_proc(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
int len = count;
if (len > 99) {
len = 99;
}
if (copy_from_user(my_str, buffer, len)) {
return -EFAULT;
}
my_str[len-1] = '\0';
return count;
}
static struct file_operations mycalc_file_ops = {
.owner = THIS_MODULE,
.read = mycalc_read_proc,
.write = mycalc_write_proc,
};
static int __init mycalc_init(void)
{
// 创建目录项
myfile_entry = proc_create(PROC_MYFILE, 0666, NULL, &mycalc_file_ops);
if (myfile_entry == NULL) {
printk(KERN_ERR "mycalc: Could not create proc entry\n");
return -ENOMEM;
}
printk(KERN_INFO "mycalc: Module loaded.\n");
return 0;
}
static void __exit mycalc_exit(void)
{
// 移除目录项
remove_proc_entry(PROC_MYFILE, NULL);
printk(KERN_INFO "mycalc: Module unloaded.\n");
}
module_init(mycalc_init);
module_exit(mycalc_exit);
在该示例中创建了一个名为proc-mycalc
的proc文件,读函数mycalc_read_proc
实现了读取指定文件的字符数和行数的功能。写函数mycalc_write_proc
实现了写入文件名的功能。这些函数都是自己实现的,没有调用任何已有的函数。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Linux内核设备驱动之proc文件系统笔记整理 - Python技术站