linux系统中的proc文件系统是一个虚拟文件系统,proc文件系统支持在应用层中通过echo,cat命令读写内核中driver的变量值。此方法可以用来调试驱动,也可以用在项目实际的需求当中。
例如:echo 192.168.3.1/24 > /proc/net/cardX # 把IP地址写到driver中,然后driver再写到网卡中。
下面例子是在driver中创建proc文件,并且在应用层中对proc文件的读写操作。
smart_nic.c
static struct proc_dir_entry *proc_dir = NULL;
struct proc_dir_entry *proc_file;
DEFINE_SPINLOCK(proc_lock);
/* 最终在应用中cat时被调用 */
static int agile_proc_read(struct seq_file *m, void *v)
{
u32 bin_addr = 0;
u32 bin_netmask = 0;
char netmask[20];
char user_str[20];
void __iomem *addr_ip = NULL;
void __iomem *addr_netmask = NULL;
//get private data
struct agile_pci_device *ap_dev = (struct agile_pci_device *)m->private;
if (!ap_dev) {
pr_err("ap_dev is null\n");
return -EFAULT;
}
spin_lock(&proc_lock);
addr_ip= get_ip_addr(ap_dev);
addr_netmask = get_netmask_addr(ap_dev);
if(addr_ip)
bin_addr = ioread32(addr_ip);
if(addr_netmask)
bin_netmask = ioread32(addr_netmask);
snprintf(netmask, sizeof(netmask), "%d", bin_netmask);
sprintf (user_str, "%s/%s", inet_ntoa(bin_addr), netmask); /* eg: user_str 192.168.1.1/24 */
seq_printf(m, "%s\n", user_str);
spin_unlock(&proc_lock);
return 0;
}
static int agile_proc_open(struct inode *inode, struct file *file)
{
/* malloc seq_operations 并初始化;
* 参3:传递private data,然后show和write中访问private data
*/
return single_open(file, agile_proc_read, PDE_DATA(inode));
}
//proc_write被调用流程:
static ssize_t agile_proc_write(struct file *fp,const char __user *u_buffer, size_t count, loff_t *data)
{
char buf[20] = {0};
size_t buf_size = min(count, sizeof(buf) - 1);
struct agile_pci_device *ap_dev = ((struct seq_file *)fp->private_data)->private;
spin_lock(&proc_lock);
if (copy_from_user(buf, u_buffer, buf_size)) {
spin_unlock(&proc_lock);
return -EFAULT;
}
buf[buf_size] = '\0';
/* 驱动中对buf数据做必要的处理 ... ... */
spin_unlock(&proc_lock);
return buf_size;
}
#if LINUX_VERSION_CODE <= KERNEL_VERSION(5,6,0)
struct file_operations proc_fops =
{
.open = agile_proc_open, /* cat called */
.read = seq_read,
.write = agile_proc_write, /* echo called */
.llseek = seq_lseek,
.release = single_release,
};
#else
static const struct proc_ops proc_fops = {
.proc_open = agile_proc_open,
.proc_read = seq_read,
.proc_write = agile_proc_write,
.proc_lseek = seq_lseek,
.proc_release = single_release,
};
#endif
/*
proc_ops 结构中函数跟踪:
seq_read()
struct seq_file *m = iocb->ki_filp->private_data;
err = m->op->show(m, p); //op : const struct seq_operations *op;
这里的show()就是在
agile_proc_open
single_open(file, agile_proc_read,,,) 中指定的show函数 agile_proc_read
single_open() //proc_ops结构中。被 proc_ops 中的 open 调用
seq_open(file, op);
*/
//创建 proc文件
static bool agile_proc_init(struct agile_pci_device *ap_dev)
{
char file_name[50] = {0};
spin_lock(&proc_lock);
sprintf(file_name, "%s%d", PROC_IP_FILE, ap_dev->proc_index);
/*create /proc/net/agile */
proc_dir = proc_mkdir(PROC_DIR, init_net.proc_net);
if(!proc_dir) {
pr_err("create /proc/net/agile err\n");
spin_unlock(&proc_lock);
return false;
}
/*create /proc/net/agile/cardIPX, X = 0,1,...; 参5:private data */
proc_file = proc_create_data(file_name, 0644, proc_dir, &proc_fops, ap_dev);
if (!proc_file) {
pr_err("create /proc/net/agile/catdIP err\n");
remove_proc_entry(PROC_DIR, NULL);
spin_unlock(&proc_lock);
return false;
}
spin_unlock(&proc_lock);
return true;
}
// 删除 /proc文件
static void agile_proc_exit(struct agile_pci_device *ap_dev)
{
char file_name[50];
int index = proc_index;
sprintf(file_name, "%s%d", PROC_IP_FILE, index);
if (proc_file) {
remove_proc_entry(file_name, proc_dir);
proc_file = NULL;
}
if (proc_dir) {
remove_proc_entry(PROC_DIR, init_net.proc_net);
proc_dir = NULL;
}
spin_unlock(&proc_lock);
}
//在probe函数中调用 agile_proc_init(); remove函数中调用 agile_proc_exit() 即可。
----------------------------------------------------------------------------
上面函数被调用的流程为:
// fs\proc\inode.c
static const struct file_operations proc_reg_file_ops = {
.read = proc_reg_read,
.write = proc_reg_write,
.open = proc_reg_open,
.release = proc_reg_release,
};
proc_reg_write()
pde_write() // fs\proc\inode.c
write = pde->proc_ops->proc_write;
return write(file, buf, count, ppos);
proc_reg_read()
pde_read() // fs\proc\inode.c
read = pde->proc_ops->proc_read;
return read(file, buf, count, ppos);
proc_reg_open()
open = pde->proc_ops->proc_open;
rv = open(inode, file);
可见 proc_ops 中的open read write等函数应该都是通过 file_operations 中的open read write函数被调用的。
注意private data的使用:
1. 在agile_proc_init() 中
proc_create_data(file_name, 0644, proc_dir, &proc_fops, ap_dev);
函数参5指定private data.
2. agile_proc_open() 中
single_open(file, agile_proc_read, PDE_DATA(inode));
函数参3需要传递PDE_DATA(inode)。
3. agile_proc_read(struct seq_file *m, void *v) 中获取private data:
struct agile_pci_device *ap_dev = (struct agile_pci_device *)m->private;
4. 同理3,在
agile_proc_write(struct file *fp,const char __user *u_buffer,
size_t count, loff_t *data)
中获取private data:
struct agile_pci_device *ap_dev = ((struct seq_file *)fp->private_data)->private;
上述代码只列出了创建和使用proc文件的代码框架,细节在使用过程中根据需求进行改进和优化。