Proc中使用seq

it2022-05-09  23

目录

测试代码代码分析 variable是全局变量,如何在proc操作间传递?总结

测试代码

#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/version.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> #include <asm/uaccess.h> static unsigned int variable; static struct proc_dir_entry *test_dir, *test_entry; #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) static int test_proc_read(char *buf, char **start, off_t off, int count, int *eof, void *data) { unsigned int *ptr_var = data; return sprintf(buf, "test_rw = %u\n", *ptr_var); } static int test_proc_write(struct file *file, const char *buffer, unsigned long count, void *data) { unsigned int *ptr_var = data; *ptr_var = simple_strtoul(buffer, NULL, 10); return count; } #else static int test_proc_show(struct seq_file *seq, void *v) { unsigned int *ptr_var = seq->private; seq_printf(seq, "%u\n", *ptr_var); return 0; } static ssize_t test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct seq_file *seq = file->private_data; unsigned int *ptr_var = seq->private; int err; char *kbuffer; if (!buffer || count > PAGE_SIZE - 1) return -EINVAL; kbuffer = (char *)__get_free_page(GFP_KERNEL); if (!kbuffer) return -ENOMEM; err = -EFAULT; if (copy_from_user(kbuffer, buffer, count)) goto out; kbuffer[count] = '\0'; *ptr_var = simple_strtoul(kbuffer, NULL, 10); return count; out: free_page((unsigned long)buffer); return err; } static int test_proc_open(struct inode *inode, struct file *file) { return single_open(file, test_proc_show, PDE_DATA(inode)); } static const struct file_operations test_proc_fops = { .owner = THIS_MODULE, .open = test_proc_open, .read = seq_read, .write = test_proc_write, .llseek = seq_lseek, .release = single_release, }; #endif static __init int test_proc_init(void) { test_dir = proc_mkdir("test_dir", NULL); if (test_dir) { #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0) test_entry = create_proc_entry("test_rw", 0666, test_dir); if (test_entry) { test_entry->nlink = 1; test_entry->data = &variable; test_entry->read_proc = test_proc_read; test_entry->write_proc = test_proc_write; return 0; } #else test_entry = proc_create_data("test_rw",0666, test_dir, &test_proc_fops, &variable); if (test_entry) return 0; #endif } return -ENOMEM; } module_init(test_proc_init); static __exit void test_proc_cleanup(void) { remove_proc_entry("test_rw", test_dir); remove_proc_entry("test_dir", NULL); } module_exit(test_proc_cleanup); MODULE_AUTHOR("Barry Song <baohua@kernel.org>"); MODULE_DESCRIPTION("proc exmaple"); MODULE_LICENSE("GPL v2");

代码分析

variable是全局变量,如何在proc操作间传递?


创建节点 proc_create_data

会生成一个proc_dir_entry,->date 用于保存&variable

static unsigned int variable; static __init int test_proc_init(void) test_entry = proc_create_data("test_rw",0666, test_dir, &test_proc_fops, &variable); pde = __proc_create(&parent, name, mode, 1); pde->proc_fops = proc_fops; pde->data = data; proc_register(parent, pde) return pde;

结论1:

test_entry->date == &variable

open阶段

PDE_DATA(inode)得到文件对应的proc_dir_entry,保存在:file->private_data->private。


file 与 seq_file
static const struct file_operations test_proc_fops = { ... .open = test_proc_open, ... }; static int test_proc_open(struct inode *inode, struct file *file) single_open(file, test_proc_show, PDE_DATA(inode)); res = seq_open(file, op); p = kmem_cache_zalloc(seq_file_cache, GFP_KERNEL); file->private_data = p; p->op = op; ((struct seq_file *)file->private_data)->private = data;

所以 file->private_date 的值为一个 struct seq_file *p; p->private = PDE_DATA(inode) 最终, file->private_date->private = PDE_DATA(inode);

PDE_DATA(inode)是什么
struct proc_inode { struct pid *pid; int fd; union proc_op op; struct proc_dir_entry *pde; struct ctl_table_header *sysctl; struct ctl_table *sysctl_entry; struct proc_ns ns; struct inode vfs_inode; }; struct proc_inode { ... struct proc_dir_entry *pde; ... } /* * General functions */ static inline struct proc_inode *PROC_I(const struct inode *inode) { return container_of(inode, struct proc_inode, vfs_inode); } static inline struct proc_dir_entry *PDE(const struct inode *inode) { return PROC_I(inode)->pde; } static inline void *__PDE_DATA(const struct inode *inode) { return PDE(inode)->data; } void *PDE_DATA(const struct inode *inode) { return __PDE_DATA(inode); } EXPORT_SYMBOL(PDE_DATA);

所以 PDE_DATA(inode)即是 container_of(inode, struct proc_inode, vfs_inode)->pde->data 其中,container_of(inode, struct proc_inode, vfs_inode)->pde 值即为 &test_entry; 那么,container_of(inode, struct proc_inode, vfs_inode)->pde->data 值即为 &test_entry->data; 根据 结论1,可知结论2

PDE_DATA(inode) = &variable

show/write 阶段,

传参为struct seq_file *seq static int test_proc_show(struct seq_file *seq, void *v) { unsigned int *ptr_var = seq->private; 传参为struct file *file static ssize_t test_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { struct seq_file *seq = file->private_data; unsigned int *ptr_var = seq->private;

总结

proc_create_data(XXX,XXX,XXX,XXX, void data); single_open(XXX, XXX, void data);

如果需要传递参数, single_open的最后一个传参必须为proc_dir_entry->data, 表示方式有:PDE_DATA(inode)、inode->datat等; 如果不需要传递数据, proc_create_data或single_open其中一个void *data为NULL;

转载于:https://www.cnblogs.com/gaoyang3513/p/10989700.html


最新回复(0)