zoukankan      html  css  js  c++  java
  • Linux内核空间-用户空间通信之debugfs

    一、debugfs文件系统简介

    debugfs虚拟文件系统是一种内核空间与用户空间的接口,基于libfs库实现,专用于开发人员调试,便于向用户空间导出内核空间数据(当然,反方向也可以)。debugfs在linux内核版本2.6.10引入,作者是Greg Kroah-Hartman。
    与procfs和sysfs不同,前者主要提供进程信息(当然后来又加入设备、内存、网络等信息,比较杂乱),后者主要提供设备信息,且有一个文件提供一个值的“规则”,是Linux通用设备模型的影射。debugfs没有类似的限制,开发者可以放入任何信息。

    二、debugfs的使用

    1. 挂载debugfs文件系统

    要使用debugfs,需要在内核编译配置中配置CONFIG_DEBUG_FS选项,一般的发行版都会默认编译进了内核,并且将其自动挂载默认的目录(/sys/kernel/debug),可通过以下命令查看:
    也可手动挂载到其它位置:
    $ mkdir /debugfs
    $ mount -t debugfs none /debugfs

    2. 利用debugfs导出基本数据类型的变量

    debugfs可以将内核中基本整数类型的变量导出为单个文件,在用户空间中可以直接对其读写(如使用cat、echo命令),只要权限允许即可。支持的类型有:u8, u16, u32, u64, size_t和 bool。其中bool类型在内核中要定义为u32类型,在用户空间中对应的文件内容则显示为Y或N。示例代码如下:
    static struct dentry *root_d = debugfs_create_dir("exam_debugfs", NULL); //在debugfs根目录下创建新目录exam_debugfs,然会新建目录的目录项指针
    static u8 var8;
    debugfs_create_u8("var-u8", 0664, root_d, &var8); //在exam_debugfs中创建变量var8对应的文件,名为var-u8,权限为0664
    static u32 varbool;
    debugfs_create_bool("var-bool", 0664, root_d, &varbool); //bool变量
    

    3. 利用debugfs导出数据块(只读)

    debugfs提供的debugfs_create_blob函数可导出数据块,示例代码如下:
    char buf[] = "Hello debugfs!
    ";
    b.data = buf;
    b.size = strlen(buf) + 1;
    debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644
    没错,debugfs提供的debugfs_blob_wrapper结构所导出的数据块只能读取,不能修改。

    4. 利用debugfs导出u32数组(只读)

    debugfs提供的debugfs_create_u32_array函数可导出内核中u32类型的数组。示例代码如下:
    u32 arr[] = {1,2,3,4,5};
    debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32));

    5. 实现可读写数据块的导出

    实现并不难,只需实现struct file_operations的open、write、read方法即可。然后调用debugfs提供的debugfs_create_file即可。该方法的原型如下:
    struct dentry* debugfs_create_file	(	const char * 	name,
    	umode_t 	mode,
    	struct dentry * 	parent,
    	void * 	data, // 传入的data指针会被赋值给新建文件对应inode的i_private字段
    	const struct file_operations * 	fops 
    )	
    下面,仿照struct debugfs_blob_wrapper的实现,实现struct my_blob_wrapper和my_blob_wrapper_ops,提供可读写的“blob”:
    /** 自定义可读写blob **/
    struct my_blob_wrapper{
        void *data;
        unsigned long size; // data缓冲区长度
    };
    static int my_blob_wrapper_open(struct inode *inode, struct file *filp)
    {
        filp->private_data = inode->i_private; // inode->i_private被设置为debugfs_create_file传入的data参数
        return 0;
    }
    static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
    {
        struct my_blob_wrapper *blob = filp->private_data;
        return simple_read_from_buffer(user_buf, count, ppos,
                blob->data, blob->size);//此函数有libfs提供,与下面逻辑等价
    //    if (*ppos >= blob->size) {
    //        return 0;
    //    }
    //    if (*ppos + count > blob->size) {
    //        count = blob->size - *ppos;
    //    }
    //    if (copy_to_user(user_buf, blob->data + *ppos, count) != 0) {
    //        return -EFAULT;
    //    }
    //    *ppos += count;
    //    return count;
    }
    static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
    {
        struct my_blob_wrapper *blob = filp->private_data;
        return simple_write_to_buffer(blob->data, blob->size, ppos,
                        user_buf, count);//此函数由libfs提供,与下面逻辑等价
    //    if (*ppos >= blob->size) {
    //        return 0;
    //    }
    //    if (*ppos + count > blob->size) {
    //        count = blob->size - *ppos;
    //    }
    //    if (copy_from_user(blob->data + *ppos, user_buf, count) != 0) {
    //        return -EFAULT;
    //    }
    //    *ppos += count;
    //    return count;
    }
    static struct file_operations my_blob_wrapper_ops = {
        .owner = THIS_MODULE,
        .open = my_blob_wrapper_open,
        .read = my_blob_wrapper_read,
        .write = my_blob_wrapper_write,
        .llseek = default_llseek,//VFS提供
    };
    struct dentry *my_create_blob(const char *name, umode_t mode,
              struct dentry *parent,
              struct my_blob_wrapper *blob)
    {
        return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops);
    }
    /* done */

    6. 注意:

    ① 在debugfs中创建的文件和目录在模块退出时,并不会自动删除,可调用debugfs_remove_recursive删除整个目录,或调用debugfs_remove删除单个文件。
    ② u32_array在用户空间文件中显示为空格隔开的元素
    ③ debugfs_create_x{8,16,32,64}与debugfs_create_u{8,16,32,64}的不同在于前者显示为16进制,后者显示为10进制

    三、debugfs示例完整代码

    #include <linux/module.h>
    #include <linux/debugfs.h>
    #include <linux/fs.h> // for libfs
    #include <asm-generic/uaccess.h>
    
    /** 自定义可读写blob **/
    struct my_blob_wrapper{
        void *data;
        unsigned long size;
    };
    static int my_blob_wrapper_open(struct inode *inode, struct file *filp)
    {
        filp->private_data = inode->i_private;
        return 0;
    }
    static ssize_t my_blob_wrapper_read(struct file *filp, char __user *user_buf, size_t count, loff_t *ppos)
    {
        struct my_blob_wrapper *blob = filp->private_data;
        return simple_read_from_buffer(user_buf, count, ppos, 
                blob->data, blob->size); // from libfs
    }
    static ssize_t my_blob_wrapper_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *ppos)
    {
        struct my_blob_wrapper *blob = filp->private_data;
        return simple_write_to_buffer(blob->data, blob->size, ppos, 
                        user_buf, count);
    }
    static struct file_operations my_blob_wrapper_ops = {
        .owner = THIS_MODULE,
        .open = my_blob_wrapper_open,
        .read = my_blob_wrapper_read,
        .write = my_blob_wrapper_write,
        .llseek = default_llseek, // from vfs
    };
    /* 接口函数 */
    struct dentry *my_create_blob(const char *name, umode_t mode,
              struct dentry *parent,
              struct my_blob_wrapper *blob)
    {
        return debugfs_create_file(name, mode, parent, blob, &my_blob_wrapper_ops);
    }
    /** my_clob implementation end **/
    
    static struct dentry *root_d;
    static u8 var8;
    static u16 var16;
    static u32 var32;
    static u32 varbool;
    static char buf[] = "Hello debugfs!
    ";
    static struct debugfs_blob_wrapper b;
    static struct my_blob_wrapper b2;
    static u32 arr[] = {1,2,3,4,5};
    
    int __init mod_init(void)
    {
        printk(KERN_INFO "exam_debugfs: initialing...
    ");
        root_d = debugfs_create_dir("exam_debugfs", NULL);
        if (!root_d) {
            printk(KERN_INFO "exam_debugfs: error create root dir
    ");
            return 1;
        }
        /* u{8,16,32}, bool */
        debugfs_create_u8("var-u8", 0664, root_d, &var8);
        debugfs_create_u16("var-u16", 0664, root_d, &var16);
        debugfs_create_u32("var-u32", 0664, root_d, &var32);
        debugfs_create_bool("var-bool", 0664, root_d, &varbool);
        /* u32_array */
        debugfs_create_u32_array("array", 0664, root_d, arr, sizeof(arr)/sizeof(u32));
        /* blob_wrapper */
        b.data = buf;
        b.size = strlen(buf) + 1;
        debugfs_create_blob("blob", 0644, root_d, &b); // blob is readonly, even if 0644
        /* my_blob_wrapper */
        b2.data = buf;
        b2.size = strlen(buf) + 1;
        my_create_blob("myblob", 0644, root_d, &b2);
    
        return 0;
    }
    void __exit mod_exit(void)
    {
        debugfs_remove_recursive(root_d);
        printk(KERN_INFO "exam_debugfs: exiting...
    ");
    }
    
    
    module_init(mod_init);
    module_exit(mod_exit);
    
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("a demo for debugfs");
    MODULE_AUTHOR("rsljdkt");
    

    四、补充:debugfs bool的实现

    static ssize_t read_file_bool(struct file *file, char __user *user_buf,
                      size_t count, loff_t *ppos)
    {
        char buf[3];
        u32 *val = file->private_data;
        
        if (*val)
            buf[0] = 'Y';
        else
            buf[0] = 'N';
        buf[1] = '
    ';
        buf[2] = 0x00;
        return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
    }
    
    static ssize_t write_file_bool(struct file *file, const char __user *user_buf,
                       size_t count, loff_t *ppos)
    {
        char buf[32];
        size_t buf_size;
        bool bv;
        u32 *val = file->private_data;
    
        buf_size = min(count, (sizeof(buf)-1));
        if (copy_from_user(buf, user_buf, buf_size))
            return -EFAULT;
    
        if (strtobool(buf, &bv) == 0)
            *val = bv;
    
        return count;
    }


    参考:


  • 相关阅读:
    You Will Be Memorizing Things
    PowerShell与cmd
    select的一些问题。
    深刻理解数据库外键含义
    html居中问题
    jsp中嵌入的html
    jdbc连接mysql报错:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column '金厉旭' in 'field list'
    [kuangbin带你飞]专题一 简单搜索
    算法竞赛训练指南11.2 最小生成树
    [kuangbin带你飞]专题六 最小生成树
  • 原文地址:https://www.cnblogs.com/pangblog/p/3283508.html
Copyright © 2011-2022 走看看