当前位置: 首页 > news >正文

Linux驱动 — 导出proc虚拟文件系统属性信息

proc文件系统

在Linux内核中,procfs(进程文件系统)是一种虚拟的文件系统,它为内核提供了一种向用户空间传递信息的方式,内核用于向用户导出内核信息,如平均负载、内存大小、存储大小等等。
驱动模块可以通过在procfs中创建文件来向用户空间提供信息或接收用户空间的输入。

虚拟文件系统内容都是动态创建的

“/proc”下的绝大多数文件是只读的 ,以显示内核信息为主

Linux系统许多命令是通过分析/proc下的文件来完成:

如ps、top、uptime和free

驱动模块中创建proc文件系统文件和属性

在驱动模块中创建procfs文件系统属性的基本步骤:

  1. 包含必要的头文件:在驱动模块的源文件中,需要包含linux/proc_fs.h和linux/fs.h头文件。
  2. 定义文件操作结构体:定义一个file_operations结构体,该结构体包含了处理proc文件的各种方法,如read、write等。
  3. 实现文件操作函数:根据需要,实现文件操作函数,如read、write等。这些函数将被用户空间的进程用来与proc文件进行交互。
  4. 创建proc文件:在驱动模块的初始化函数中,使用proc_create或create_proc_entry函数创建proc文件。这些函数需要文件名、权限和一个指向file_operations结构体的指针。
  5. 注册proc文件:在创建proc文件后,需要将其注册到内核的procfs中。这通常在驱动模块的初始化函数中完成。
  6. 在proc文件中存储数据:如果需要在proc文件中存储数据,可以在file_operations结构体的read和write函数中实现数据的读写。
  7. 清理proc文件:在驱动模块的退出函数中,使用remove_proc_entry函数清理proc文件,以防止内存泄漏。
    在驱动模块中创建一个proc文件,并通过该文件向用户空间传递一个字符串:
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/fs.h>#define PROCFS_NAME "my_proc_file"static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos);
static ssize_t proc_write(struct file *file, const char __user *usr_buf, size_t count, loff_t *pos);static struct file_operations proc_ops = {.owner = THIS_MODULE,.read = proc_read,.write = proc_write,
};static int __init my_module_init(void) {proc_create(PROCFS_NAME, 0666, NULL, &proc_ops);printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);return 0;
}static void __exit my_module_exit(void) {remove_proc_entry(PROCFS_NAME, NULL);printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
}static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos) {int rv = 0;char *msg = "Hello from kernel space!\n";if (*pos >= strlen(msg))return 0;if (count > strlen(msg) - *pos)count = strlen(msg) - *pos;if (copy_to_user(usr_buf, msg + *pos, count))return -EFAULT;*pos += count;rv = count;return rv;
}static ssize_t proc_write(struct file *file, const char __user *usr_buf, size_t count, loff_t *pos) {// Implement write functionality if neededreturn -EINVAL;
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple example of creating a proc file");
MODULE_AUTHOR("Your Name");
[RSU7032: customer]# insmod proc_file.ko
[RSU7032: customer]# lsmod
proc_file 1168 0 - Live 0xbf002000 (O)
sdxxx 543084 1 - Live 0xbf07c000 (O)
mlan 432260 1 sdxxx, Live 0xbf004000 (O)
rsu7012_iomux 2481 0 - Live 0xbf000000 (O)
[RSU7032: customer]# cat /proc/my_proc_file
Hello from kernel space!

在这个示例中,我们创建了一个名为my_proc_file的proc文件,用户可以通过读取这个文件来获取内核空间的消息。在proc_read函数中,我们实现了将消息从内核空间复制到用户空间的功能。在proc_write函数中,我们简单地返回了一个错误代码,表示不支持写入操作。
实际使用时可能需要根据具体需求进行修改和扩展。

从Linux 3.10开始,推荐使用proc_create_dataremove_proc_entry函数来创建和删除proc文件,因为proc_createcreate_proc_entry函数已被标记为过时。

从Linux 3.10开始,proc_createcreate_proc_entry函数已被标记为过时,推荐使用proc_create_dataremove_proc_entry函数来创建和删除proc文件。以下是使用proc_create_data的示例

#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/uaccess.h>
#include <linux/fs.h>#define PROCFS_NAME "my_proc_file"static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos);
static ssize_t proc_write(struct file *file, const char __user *usr_buf, size_t count, loff_t *pos);static struct file_operations proc_ops = {.owner = THIS_MODULE,.read = proc_read,.write = proc_write,
};static int __init my_module_init(void) {proc_create_data(PROCFS_NAME, 0666, NULL, &proc_ops, NULL);printk(KERN_INFO "/proc/%s created\n", PROCFS_NAME);return 0;
}static void __exit my_module_exit(void) {remove_proc_entry(PROCFS_NAME, NULL);printk(KERN_INFO "/proc/%s removed\n", PROCFS_NAME);
}static ssize_t proc_read(struct file *file, char __user *usr_buf, size_t count, loff_t *pos) {int rv = 0;char *msg = "Hello from kernel space!\n";if (*pos >= strlen(msg))return 0;if (count > strlen(msg) - *pos)count = strlen(msg) - *pos;if (copy_to_user(usr_buf, msg + *pos, count))return -EFAULT;*pos += count;rv = count;return rv;
}static ssize_t proc_write(struct file *file, const char __user *usr_buf, size_t count, loff_t *pos) {// Implement write functionality if neededreturn -EINVAL;
}module_init(my_module_init);
module_exit(my_module_exit);MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("A simple example of creating a proc file");
MODULE_AUTHOR("Your Name");

创建proc文件系统属性,实现读取
在 Linux 4.0 内核驱动中,虽然官方已不鼓励继续向 /proc 里添加新条目(官方推荐用 /sys 或 debugfs),但如果出于兼容性目的仍想在 /proc 里创建可读属性,可按下面步骤完成。核心思路是:

  1. 在模块初始化时创建目录及文件(proc_mkdir / proc_create)。
  2. 实现一个 read_proc(老接口)或 .read(seq_file 新接口)函数,把内核数据拷贝给用户。
  3. 清理时把目录/文件删掉即可。
    下面给出两种写法,任选其一即可编译通过。
    3.10 以后内核主推的 seq_file 接口
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>static int my_val = 42;          /* 要暴露给用户的值 *//* seq_show 会被多次调用,直到返回 0 */
static int my_proc_show(struct seq_file *m, void *v)
{seq_printf(m, "%d\n", my_val);return 0;
}static int my_proc_open(struct inode *inode, struct file *file)
{/* 单 open 接口,内部已经帮你完成所有 seq_file 初始化 */return single_open(file, my_proc_show, NULL);
}static const struct file_operations my_proc_fops = {.owner   = THIS_MODULE,.open    = my_proc_open,.read    = seq_read,.llseek  = seq_lseek,.release = single_release,
};static struct proc_dir_entry *my_dir;
static struct proc_dir_entry *my_file;static int __init my_init(void)
{/* 1. 创建 /proc/my_drv 目录 */my_dir = proc_mkdir("my_drv", NULL);if (!my_dir)return -ENOMEM;/* 2. 在目录里创建 read-only 文件 */my_file = proc_create("val", 0444, my_dir, &my_proc_fops);if (!my_file) {proc_remove(my_dir);return -ENOMEM;}return 0;
}static void __exit my_exit(void)
{proc_remove(my_file);   /* 也可直接 proc_remove(my_dir) 把目录一起删 */proc_remove(my_dir);
}module_init(my_init);
module_exit(my_exit);
MODULE_LICENSE("GPL");

Mafile:

KERNEL_DIR = /home/xgj/workspace/project/rsu7012/kernel/linux-3.10.79export PATH := $(PATH):/home/xgj/workspace/project/rsu7012/toolchains/arm-eabi/binARCH=arm
CROSS_COMPILE=arm-eabi-
export  ARCH  CROSS_COMPILEobj-m += proc_attr.obuild: proc_attr proc_attr:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) modules.PHONY:clean
clean:$(MAKE) -C $(KERNEL_DIR) M=$(CURDIR) clean

测试:

[RSU7032: customer]# insmod proc_attr.ko
[RSU7032: customer]# lsmod
proc_attr 1008 0 - Live 0xbf071000 (O)
proc_file 1168 0 - Live 0xbf002000 (O)
sdxxx 543084 1 - Live 0xbf07c000 (O)
mlan 432260 1 sdxxx, Live 0xbf004000 (O)
rsu7012_iomux 2481 0 - Live 0xbf000000 (O)
[RSU7032: customer]# cat /proc/m
meminfo       misc          modules       mounts        mwlan/        my_drv/       my_proc_file
[RSU7032: customer]# cat /proc/my_drv/val
42
http://www.dtcms.com/a/353351.html

相关文章:

  • LabVIEW 音频信号处理
  • 【ElasticSearch】原理分析
  • opencv+yolov8n图像模型训练和推断完整代码
  • django注册app时两种方式比较
  • PyTorch图像预处理完全指南:从基础操作到GPU加速实战
  • jQuery版EasyUI的ComboBox(下拉列表框)问题
  • 通义万相音频驱动视频模型Wan2.2-S2V重磅开源
  • 聊一聊 单体分布式 和 微服务分布式
  • Package.xml的字段说明
  • 前端架构知识体系:css架构模式和代码规范
  • 趣味学习Rust基础篇(用Rust做一个猜数字游戏)
  • PAT 1087 All Roads Lead to Rome
  • 嵌入式学习资料分享
  • java中的数据类型
  • 《FastAPI零基础入门与进阶实战》第14篇:ORM之第一个案例改善-用户查询
  • 【图文介绍】PCIe 6.0 Retimer板来了!
  • 快速上手对接币安加密货币API
  • 《Linux 网络编程四:TCP 并发服务器:构建模式、原理及关键技术(以select )》
  • 3 无重复字符的最长子串
  • Windows系统之不使用第三方软件查看电脑详细配置信息
  • 基于linux系统的LIRC库学习笔记
  • Ubuntu 的磁盘管理
  • [java] 控制三个线程按顺序交替输出数字1、2、3
  • 【新版发布】Apache DolphinScheduler 3.3.1 正式上线:更稳、更快、更安全!
  • TensorFlow 面试题及详细答案 120道(21-30)-- 模型构建与神经网络
  • 数据结构:创建堆(或者叫“堆化”,Heapify)
  • 增强CD47检查点免疫治疗:高通量发现增强巨噬细胞吞噬作用的小分子协同剂
  • nestjs 连接redis
  • HIVE的Window functions窗口函数【一】
  • 手写题(面试)