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


    参考:


  • 相关阅读:
    permission 文档 翻译 运行时权限
    TabLayout ViewPager Fragment 简介 案例 MD
    Log 日志工具类 保存到文件 MD
    OkHttp 官方wiki 翻译 MD
    Okhttp 简介 示例 MD
    OkHttp 官方Wiki之【使用案例】
    DialogPlus
    倒计时 总结 Timer Handler CountDownTimer RxJava MD
    RecyclerView 判断滑到底部 顶部 预加载 更多 分页 MD
    CSS3的媒体查询(Media Queries)与移动设备显示尺寸大全
  • 原文地址:https://www.cnblogs.com/pangblog/p/3283508.html
Copyright © 2011-2022 走看看