Linux驱动编程 - procfs创建接口

目录

简介:

一、/proc下创建目录或文件

1、proc_create

1.1 函数介绍

1.1.1 proc_create()

1.1.2 proc_mkdir()

1.1.3 proc_remove()

1.2 示例

1.2.1 示例1

1.2.2 示例2

2、create_proc_entry

2.1 函数介绍

2.2 实例


简介:


        Linux系统上的/proc目录是一种文件系统,即procfs文件系统。与其它常见的文件系统不同的是,/proc是一种伪文件系统(也即虚拟文件系统),存储的是当前内核运行状态的一系列特殊文件,用户可以通过这些文件查看有关系统硬件及当前正在运行进程的信息,甚至可以通过更改其中某些文件来改变内核的运行状态。

         /proc文件系统包含了一些目录(用作组织信息的方式)和虚拟文件。虚拟文件可以向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。本文介绍如何在/proc创建读、写接口。

一、/proc下创建目录或文件


        proc文件的创建有两种方式:proc_create  create_proc_entry。kernel 3.10之前的版本用 create_proc_entry 创建proc文件,新版本create_proc_entry被删除,用proc_create替代create_proc_entry。

1、proc_create


新版本Linux使用 proc_create 创建 /proc 文件

1.1 函数介绍


1.1.1 proc_create()
struct proc_dir_entry *proc_create(const char *name, umode_t mode,
				   struct proc_dir_entry *parent,
				   const struct file_operations *proc_fops)
{
	return proc_create_data(name, mode, parent, proc_fops, NULL);
}

功能:创建proc文件,并将proc文件和fops操作集绑定

参数:

  • *name:创建proc文件的名字
  • mode:读写权限,例如:读、写、执行
  • *parent:父目录,如果为NULL,会在/proc创建proc文件
  • *proc_fops:文件的操作集合,具体可参考例子

返回值:返回当前proc文件的入口结构体

1.1.2 proc_mkdir()
struct proc_dir_entry *proc_mkdir(const char *name,
		struct proc_dir_entry *parent)
{
	return proc_mkdir_data(name, 0, parent, NULL);
}

功能:在proc下创建目录

参数:

  • *name:创建proc目录的名称
  • *parent:父目录

返回值:返回当前目录的入口结构体

1.1.3 proc_remove()
void proc_remove(struct proc_dir_entry *de)
{
	if (de)
		remove_proc_subtree(de->name, de->parent);
}

功能:删除一个已存在的 procfs 文件或目录

1.2 示例


        创建proc文件需要实现file_operation结构体,主要实现read和write就可以了。然后通过proc_create将模块注册到内核。/proc目录下就会生成创建的文件。
        对该文件进行读写就能实现用户进程与内核的通信。

1.2.1 示例1
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <asm/io.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/proc_fs.h>
#include <linux/slab.h>
#include <linux/seq_file.h> 
 
struct proc_dir_entry *hello_proc = NULL;
struct proc_dir_entry *hello_dir = NULL;
 
/* 定义全局数组保存用户空间写入的数据 */
static char hello_data[20] = "hello world";
 
static ssize_t hello_proc_open(struct inode *inode, struct file *file)
{
	printk("%s run\n", __func__);
	return 0;
}
 
/* 如果使用cat节点会调用该函数
 */
static ssize_t hello_proc_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
	int ret = 0;
	
	ret = copy_to_user(buf, hello_data, strlen(hello_data));
	if (ret != 0)
	{
		printk("%s: copy_to_user failed!\n", __func__);
		return -EFAULT;
	}
	
	printk("%s: %s\n", __func__, buf);
	return 0;
}
 
/* 用户空间使用echo往此节点写入数据 */
static ssize_t hello_proc_write(struct file *file, const char __user *buf, size_t size, loff_t * ppos)
{
	int ret;
 
	ret = copy_from_user(hello_data, buf, size);
	if (ret != 0)
	{
		printk("copy_from_user failed!\n");
		return -EFAULT;
	}
	printk("%s: hello_data is %s", __func__, hello_data);
    
	return 0;
}

/* 定义一个file_operations结构体变量 */
static const struct file_operations hello_proc_fops = {
	.owner	= THIS_MODULE,
	.open	= hello_proc_open,	//用户态调用open函数
	.read	= hello_proc_read,	//使用cat时调用
	.write	= hello_proc_write,	//使用echo时调用
};
 
static int __init proc_test_init(void)
{
	/* 创建 /proc/hello_dir 目录 */
	hello_dir = proc_mkdir("hello_dir",NULL);
	if(hello_dir == NULL){
		printk("%s: proc_mIkdir failed: %s\n", __func__,  "hello_dir");
		return -EINVAL;
	}
	
	/* 创建 /proc/hello_dir/hello_proc 文件,并设置文件操作集 */
	hello_proc = proc_create("hello_proc", 0666, hello_dir, &hello_proc_fops);
	if (hello_proc == NULL) {
		printk("%s: proc_create failed: %s\n", __func__, "hello_proc");
		proc_remove(hello_dir);		// hello_proc 文件创建失败,删除上一步创建的文件夹 hello_dir
		return -EINVAL;
	}

	return 0;
}

static void __exit proc_test_exit(void)
{
	/* 删除文件 */
	if(hello_proc)
		proc_remove(hello_proc);

  /* 删除文件夹 */
  if(hello_dir)
		proc_remove(hello_dir);
}

module_init(proc_test_init);
module_exit(proc_test_exit);
MODULE_LICENSE("GPL");

用户空间使用echo命令时会调用到 hello_proc_write。使用cat节点会调用 hello_proc_read。

测试结果:

/ # insmod procfs_test.ko                        # 加载模块
/ # cat /proc/hello_dir/hello_proc             # cat 读
hello_proc_open run
hello_proc_read: hello world
/ # 
/ # echo "proc_test" > /proc/hello_dir/hello_proc        # echo写
/ # cat /proc/hello_dir/hello_proc              # cat读
hello_proc_open run
hello_proc_read: proc_test

1.2.2 示例2

procfs通常会和seq_file接口一起使用。

示例功能:获取cmdline中自定义变量,并通过procfs接口使用seq_file方式读取info_value的值

/* 获取cmdline中自定义变量,并通过procfs接口使用seq_file方式读取info_value的值 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>

struct proc_dir_entry *my_proc_entry;

/* 获取cmdline中的值 */
static char cmdline_info_value = 0;
static int __init cmdline_info_setup(char *str)
{
	sscanf(str, "%d", &cmdline_info_value);

	return 0;
}
__setup("info_value=", cmdline_info_setup);

static int info_value_show(struct seq_file *m, void *v)
{
    seq_printf(m, "%d\n", cmdline_info_value);

    return 0;
}

static int proc_test_open(struct inode *inode, struct file *filp)
{
    return single_open(filp, info_value_show, NULL);
}

static const struct file_operations proc_test_fops = {
	.owner      = THIS_MODULE,
	.open       = proc_test_open,
	.read       = seq_read,
	.llseek     = seq_lseek,
    .release    = single_release,
};

static int __init my_module_init(void)
{
    /* 创建 /proc/info_value 文件 */
    my_proc_entry = proc_create("info_value", 0660, NULL, &proc_test_fops);
    if(!my_proc_entry ){
        printk("%s,%s: proc_create failed: %s\n", __func__, "info_value");
		return -EIO
	}

    return 0;
}

static void __exit my_module_exit(void)
{
   proc_remove(my_proc_entry);
}

module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");

2、create_proc_entry


Linux 3.10之后的版本create_proc_entry被删除,用proc_create替代create_proc_entry。下面简单介绍下 3.10之前版本如何使用 create_proc_entry。

2.1 函数介绍


2.1.1 创建文件

struct proc_dir_entry *create_proc_entry(constchar *name, mode_t mode, struct proc_dir_entry *parent)

2.1.2 删除文件/目录

void remove_proc_entry(const char *name, struct proc_dir_entry *parent)

2.2 示例

#include <linux/module.h>
#include <linux/sched.h>	//jiffies
#include <linux/proc_fs.h>
#include <linux/uaccess.h>	//copy_to_user()|copy_from_user()
 
static char *str = NULL;
 
//proc文件的读函数
static int my_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data)
{
	int ret = 0;
	ret = sprintf(buf, "jiffies = %ld\n", jiffies);
	ret += sprintf(buf + ret, "str = %s\n", str);
 
	return ret;
}
 
//proc文件的写函数
static int my_proc_write(struct file *filp, const char __user *buf, unsigned long count, void *data)
{
	//分配临时缓冲区
	char *tmp = kzalloc((count+1), GFP_KERNEL);
	if (!tmp)
		return -ENOMEM;
 
	//将用户态write的字符串拷贝到内核空间
	if (copy_from_user(tmp, buf, count)) {
		kfree(tmp);
		return -EFAULT;
	}
 
	//将str的旧空间释放,然后将tmp赋值给str
	if (str) {
		kfree(str);
	}
	str = tmp;
 
	return count;
}
 
struct proc_dir_entry *proc_file = NULL;
static int __init create_proc_init(void)
{
	//创建proc文件
	proc_file = create_proc_entry("proc_file", 0666, NULL);
	if (!proc_file) {
		printk("Cannot create /proc/proc_file\n");
		return -ENOMEM;
	}
 
	//将 /proc/proc_file 文件和读写函数关联
	proc_file->read_proc = my_proc_read;
	proc_file->write_proc = my_proc_write;
 
	return 0;
}
 
static void __exit create_proc_exit(void)
{
	//删除proc文件
	if (proc_file) {
		remove_proc_entry("proc_file", NULL);
	}
	if (str) {
		kfree(str);
	}
}
 
module_init(create_proc_init);
module_exit(create_proc_exit);
MODULE_LICENSE("GPL");

参考文档:

Linux驱动 | procfs接口创建


`proc_create`是一个函数,用于在`/proc`目录下创建一个新的proc文件。它的语法如下: ```c struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent, const struct file_operations *proc_fops); ``` 其中,`name`是要创建的proc文件的名称,`mode`是文件的访问权限,`parent`是要将文件添加到的父目录,`proc_fops`是一个指向文件操作结构的指针,用于定义文件的操作。 下面是一个示例,演示如何使用`proc_create`函数创建一个名为`mytest`的proc文件: ```c #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/uaccess.h> #define MYTEST_PROC_FILE "mytest" static struct proc_dir_entry *mytest_proc_file; static ssize_t mytest_proc_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { // 读取文件内容并将其写入用户空间缓冲区 return 0; } static ssize_t mytest_proc_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { // 从用户空间缓冲区读取数据并将其写入文件 return count; } static const struct file_operations mytest_proc_file_fops = { .owner = THIS_MODULE, .read = mytest_proc_file_read, .write = mytest_proc_file_write, }; static int __init mytest_init(void) { // 在/proc目录下创建mytest文件 mytest_proc_file = proc_create(MYTEST_PROC_FILE, 0666, NULL, &mytest_proc_file_fops); if (!mytest_proc_file) { printk(KERN_ERR "Failed to create /proc/%s\n", MYTEST_PROC_FILE); return -ENOMEM; } printk(KERN_INFO "/proc/%s created\n", MYTEST_PROC_FILE); return 0; } static void __exit mytest_exit(void) { // 删除mytest文件 proc_remove(mytest_proc_file); printk(KERN_INFO "/proc/%s removed\n", MYTEST_PROC_FILE); } module_init(mytest_init); module_exit(mytest_exit); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值