1 2 3 4

procfs | 给驱动添加和用户空间交互的文件

什么是proc

linux 操作系统把虚拟地址分为用户空间和内核空间,内核空间可以通过procfs把内核的数据呈现给用户空间,用户空间也可以把数据写入到内核从而更改内核的行为,这在驱动中很常见,最终目的就是app就能通过读写procfs的文件和内核交互。

procfs是基于内存的文件系统,意味着掉电就会丢失,因此只能更改运行的行为和查看运行时的状态,一般都是用来查看动态的数据,大多数是只读的,当然这个可以设置。

procfs存在于系统中/proc目录中,可以通过mount 查看

mount
...
proc on /proc type proc (rw,relatime)
...

常见proc文件

  • /proc/devices 已经注册了的字符设备和块设备的住设备号
  • /proc/iomem 系统能感知到的物理地址和总线设备地址,会包含外设的地址
  • /proc/ioports I/O空间的地址,ARM中没有IO空间,因此是X86架构使用
  • /proc/interrupts 已经注册了的中断的信息
  • /proc/softirqs 已经注册了的softirq
  • /proc/swaps 当前有效的swaps
  • /proc/kallsyms 运行时的内核的符号,包括已经加载驱动的符号
  • /proc/partitions 当前已经连接的块设备和它们的分区
  • /proc/partitions 当前内核可以识别的文件系统
  • /proc/cpuinfo cpu信息

创建proc目录

使用这个API来创建一个proc目录:

struct proc_dir_entry *proc_mkdir(const char *name, struct proc_dir_entry *parent);
  • name :在创建目录的名字
  • parent:在哪个目录下创建目录,如果传入NULL,则在/proc下创建

返回一个表示你要创建的目录的对象proc_dir_entry ,一个proc_dir_entry 表示一个proc目录或者一个proc文件。

创建一个proc文件

使用这个API来创建一个文件:

static inline struct proc_dir_entry *
proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent,
	    const struct proc_ops *proc_ops)
  • name 要创建文件的名字
  • mode :此文件的默认权限
  • parent : 要在哪个目录下创建文件,如果为NULL ,则在/proc下创建
  • proc_ops :此文件的操作集合

struct proc_ops类似于设备驱动中的文件操作集合,也就是open /read那些,在这里面实现读取,控制逻辑。

完整demo

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include<linux/proc_fs.h>

static struct proc_dir_entry *parent;
static char etx_array[100] = "justice hello\n";
static int len =1;

static int open_proc(struct inode *inode, struct file *file)
{
    pr_info("proc file opend.....\t");
    return 0;
}

static int release_proc(struct inode *inode, struct file *file)
{
    pr_info("proc file released.....\n");
    return 0;
}

static ssize_t read_proc(struct file *filp, char __user *buffer, size_t length,loff_t * offset)
{
    pr_info("proc file read.....\n");
	
	printk("offset (%d),length (%d)\n",*offset,length );
	if(*offset >= 100)
	{
		pr_info("file end!\n");
		return 0;
	}
	
	if(length > 100 - *offset)
		length = 100 - *offset;

	*offset += length;
    if(copy_to_user(buffer,etx_array,100) )
    {
        pr_err("Data Send : Err!\n");
    }
 	pr_info("read end\n");
    return length;
}

static ssize_t write_proc(struct file *filp, const char *buff, size_t len, loff_t * off)
{
    pr_info("proc file wrote.....\n");

	memset(etx_array, 0, 100);
	
    if( copy_from_user(etx_array,buff,len) )
    {
        pr_err("Data Write : Err!\n");
    }
    
    return len;
}

const struct proc_ops proc_ops = {
	.proc_open = open_proc,
    .proc_read = read_proc,
    .proc_write = write_proc,
    .proc_release = release_proc,
};
	
static int __init procfs_init(void)
{
	parent = proc_mkdir("procfs-test", NULL);
	if( parent == NULL )
    {
            pr_info("Error creating proc entry");
            return -EINVAL;
    }

	proc_create("lzy", 0666, parent, &proc_ops);

	return 0;
}

static void __exit procfs_exit(void)
{
	 proc_remove(parent);
}
module_init(procfs_init);
module_exit(procfs_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("lzy");
MODULE_DESCRIPTION("Simple Linux device driver (procfs)");
MODULE_VERSION("1.6");

在这个例子中,通过读写/proc/procfs-test/lzy文件来读写字符串数字etx_array的内容,要注意的是,proc_ops .proc_read 需要小心处理传入的length和offset。

上层的app,比如cat工具都这个文件的话,length就是传入了4096字节,远远大于我们的数组内容,需要处理何时返回0,意味着本文件已经读完了,cat 的设计就是把文件读完,如果返回的值一直不为0的话,cat程序就会一直读一直读没有停止的时候。

可以加我好友哦

posted @   研究生小逸  阅读(170)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示