procfs(进程文件系统)是Linux内核提供的一种伪文件系统,允许内核向用户空间导出运行时信息。在驱动开发中,创建procfs接口是一种常见的与用户空间通信的方式。
#include <linux/proc_fs.h>
#include <linux/seq_file.h> // 用于seq_file接口
// 定义proc文件操作结构体
static const struct proc_ops my_proc_fops = {
.proc_open = my_proc_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
// 在模块初始化函数中创建proc文件
static int __init my_module_init(void)
{
proc_create("my_proc_file", 0, NULL, &my_proc_fops);
return 0;
}
// 在模块退出函数中删除proc文件
static void __exit my_module_exit(void)
{
remove_proc_entry("my_proc_file", NULL);
}
static int my_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "Driver information:\n");
seq_printf(m, "Version: 1.0\n");
seq_printf(m, "Status: Active\n");
return 0;
}
static int my_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, my_proc_show, NULL);
}
static struct proc_dir_entry *my_proc_dir;
static int __init my_module_init(void)
{
// 创建proc目录
my_proc_dir = proc_mkdir("my_driver", NULL);
if (!my_proc_dir)
return -ENOMEM;
// 在目录下创建文件
proc_create("status", 0, my_proc_dir, &my_proc_fops);
return 0;
}
static void __exit my_module_exit(void)
{
remove_proc_entry("status", my_proc_dir);
remove_proc_entry("my_driver", NULL);
}
static ssize_t my_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char data[128];
if (count >= sizeof(data))
return -EINVAL;
if (copy_from_user(data, buffer, count))
return -EFAULT;
data[count] = '\0';
// 处理写入的数据
printk(KERN_INFO "Received: %s\n", data);
return count;
}
static const struct proc_ops my_rw_proc_fops = {
.proc_open = my_proc_open,
.proc_read = seq_read,
.proc_write = my_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
对于大量数据的输出,建议使用seq_file接口:
static int my_seq_show(struct seq_file *m, void *v)
{
int i;
for (i = 0; i < 100; i++) {
seq_printf(m, "Item %d\n", i);
}
return 0;
}
static int my_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, my_seq_show, NULL);
}
static const struct proc_ops my_seq_fops = {
.proc_open = my_seq_open,
.proc_read = seq_read,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
权限控制:通过proc_create_data
的mode参数设置文件权限
proc_create("config", 0644, my_proc_dir, &my_rw_proc_fops);
私有数据:使用proc_create_data
传递私有数据
proc_create_data("status", 0, my_proc_dir, &my_proc_fops, my_private_data);
大文件处理:对于可能很大的输出,总是使用seq_file接口
安全性:
copy_from_user
/copy_to_user
进行用户空间和内核空间的数据交换资源清理:确保在模块退出时删除所有创建的proc条目
虽然procfs仍然广泛使用,但Linux社区推荐在新代码中使用sysfs(/sys)或debugfs(/sys/kernel/debug)作为替代,特别是:
procfs更适合于进程相关的信息或传统接口的兼容性维护。
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
#define PROC_DIR "my_driver"
#define PROC_FILE "status"
static struct proc_dir_entry *my_proc_dir;
static char driver_status[128] = "Initialized";
static int my_proc_show(struct seq_file *m, void *v)
{
seq_printf(m, "Current status: %s\n", driver_status);
return 0;
}
static int my_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, my_proc_show, NULL);
}
static ssize_t my_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
if (count >= sizeof(driver_status))
return -EINVAL;
if (copy_from_user(driver_status, buffer, count))
return -EFAULT;
driver_status[count] = '\0';
return count;
}
static const struct proc_ops my_proc_fops = {
.proc_open = my_proc_open,
.proc_read = seq_read,
.proc_write = my_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
static int __init my_module_init(void)
{
my_proc_dir = proc_mkdir(PROC_DIR, NULL);
if (!my_proc_dir)
return -ENOMEM;
if (!proc_create(PROC_FILE, 0644, my_proc_dir, &my_proc_fops)) {
remove_proc_entry(PROC_DIR, NULL);
return -ENOMEM;
}
printk(KERN_INFO "Procfs interface created\n");
return 0;
}
static void __exit my_module_exit(void)
{
remove_proc_entry(PROC_FILE, my_proc_dir);
remove_proc_entry(PROC_DIR, NULL);
printk(KERN_INFO "Procfs interface removed\n");
}
module_init(my_module_init);
module_exit(my_module_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Example procfs interface");
这个示例展示了如何创建一个可读写的procfs接口,包含目录创建、权限设置和基本的数据交换功能。