首页 > 其他 > 详细

Proc中使用seq_file,数据如何传递

时间:2019-06-08 09:32:37      阅读:112      评论:0      收藏:0      [点我收藏+]
#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;

所以

test_entry->date == &variable           // 标注1,

open阶段

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

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;
};

/*
 * 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

struct proc_inode {
    ...
    struct proc_dir_entry *pde;
    ...
}

所以inode->i_private
inode = inode_of(file)
PDE_DATA(inode) 的struct proc_dir_entry *pde;
pde

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;

结论1

如果不想传递参数, void *data 填入NULL。
proc_create_data(XXX,XXX,XXX,XXX, data);
open阶段中的PDE_DATA(inode),可以忽略。
single_open(XXX, XXX, PDE_DATA(inode));

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

扩展,

struct proc_dir_entry proc_create_data(const char name, umode_t mode,
struct proc_dir_entry parent,
const struct file_operations
proc_fops, void data)
{
struct proc_dir_entry
p;

BUG_ON(proc_fops == NULL);

p = proc_create_reg(name, mode, &parent, data);
if (!p)
    return NULL;
p->proc_fops = proc_fops;
return proc_register(parent, p);

}
EXPORT_SYMBOL(proc_create_data);
```

Proc中使用seq_file,数据如何传递

原文:https://www.cnblogs.com/gaoyang3513/p/10989700.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!