• linux的debugfs


    DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。(类似的虚拟文件系统还有procfs和sysfs等!procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。)。虚拟文件系统都并不实际存储在硬盘上,而是Linux内核运行起来后才建立起来。

    默认情况下,debugfs会被挂载在目录/sys/kernel/debug之下,如果您的发行版里没有自动挂载,可以用如下命令手动完成:

    # mount -t debugfs none /your/debugfs/dir
    Linux内核为debugfs提供了非常简洁的API,本文接下来将以一个实作为例来介绍,sample code可以从这里下载。

    这个实作会在debugfs中建立如下的目录结构:

    其中,a对应模块中的一个u8类型的变量,b和subdir下面的c都是对应模块里的一个字符数组,只是它们的实现方式不同。

    在module_init里,我们首先要建立根目录mydebug:

    1
    my_debugfs_root = debugfs_create_dir("mydebug", NULL);

    第一个参数是目录的名称,第二个参数用来指定这个目录的上级目录,如果是NULL,则表示是放在debugfs的根目录里。

    子目录也是用debugfs_create_dir来实现:

    1
    sub_dir = debugfs_create_dir("subdir", my_debugfs_root);

    建立文件a的代码非常简单:

    1
    debugfs_create_u8("a", 0644, my_debugfs_root, &a);

    这表示文件名为“a”,文件属性是0644,父目录是上面建立的“mydebug”,对应的变量是模块中的a。

    Linux内核还提供了其他一些创建debugfs文件的API,请参考本文的附录。

    b是一个32-bytes的字符数组,在debugfs里,数组可以用blob wrapper来实现。

    1
    2
    3
    4
    5
    6
    char hello[32] = "Hello world!\n";
    struct debugfs_blob_wrapper b;
    b.data = (void *)hello;
    b.size = strlen(hello) + 1;
    debugfs_create_blob("b", 0644, my_debugfs_root, &b);

    这里需要注意的是,blob wrapper定义的数据只能是只读的。在本例中,虽然我们把文件b的权限设定为0644,但实际这个文件还是只读的,如果试图改写这个文件,系统将提示出错。

    如果需要对内核数组进行写的动作,blob wrapper就无法满足要求,我们只能通过自己定义文件操作来实现。在这个实作里,可以参考文件c的实现。c和b在模块里对应着同一块字符数组,不同的是,b是只读的,而c通过自定义的文件操作同时实现了读和写。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    static int c_open(struct inode *inode, struct file *filp)
    {
    filp->private_data = inode->i_private;
    return 0;
    }
    static ssize_t c_read(struct file *filp, char __user *buffer,
    size_t count, loff_t *ppos)
    {
    if (*ppos >= 32)
    return 0;
    if (*ppos + count > 32)
    count = 32 - *ppos;
    if (copy_to_user(buffer, hello + *ppos, count))
    return -EFAULT;
    *ppos += count;
    return count;
    }
    static ssize_t c_write(struct file *filp, const char __user *buffer,
    size_t count, loff_t *ppos)
    {
    if (*ppos >= 32)
    return 0;
    if (*ppos + count > 32)
    count = 32 - *ppos;
    if (copy_from_user(hello + *ppos, buffer, count))
    return -EFAULT;
    *ppos += count;
    return count;
    }
    struct file_operations c_fops = {
    .owner = THIS_MODULE,
    .open = c_open,
    .read = c_read,
    .write = c_write,
    };
    debugfs_create_file("c", 0644, sub_dir, NULL, &c_fops);

    注:代码里,c_open其实并没有任何用处,因为c_read和c_write直接引用了全局变量hello。这里,我们也可以换一种写法,在read/write函数里用filp->private_data来引用字符数组hello。

    到这里,三个文件和子目录已经创建完毕。在module_exit中,我们要记得释放创建的数据。

    1
    debugfs_remove_recursive(my_debugfs_root);

    debugfs_remove_recursive可以帮我们逐步移除每个分配的dentry,如果您想一个一个手动的移除,也可以直接调用debugfs_remove。

    附录:

    创建和撤销目录及文件

    1
    2
    3
    4
    5
    6
    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
    struct dentry *debugfs_create_file(const char *name, mode_t mode,
    struct dentry *parent, void *data,
    const struct file_operations *fops);
    void debugfs_remove(struct dentry *dentry);
    void debugfs_remove_recursive(struct dentry *dentry);

    创建单值文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    struct dentry *debugfs_create_u8(const char *name, mode_t mode,
    struct dentry *parent, u8 *value);
    struct dentry *debugfs_create_u16(const char *name, mode_t mode,
    struct dentry *parent, u16 *value);
    struct dentry *debugfs_create_u32(const char *name, mode_t mode,
    struct dentry *parent, u32 *value);
    struct dentry *debugfs_create_u64(const char *name, mode_t mode,
    struct dentry *parent, u64 *value);
    struct dentry *debugfs_create_x8(const char *name, mode_t mode,
    struct dentry *parent, u8 *value);
    struct dentry *debugfs_create_x16(const char *name, mode_t mode,
    struct dentry *parent, u16 *value);
    struct dentry *debugfs_create_x32(const char *name, mode_t mode,
    struct dentry *parent, u32 *value);
    struct dentry *debugfs_create_size_t(const char *name, mode_t mode,
    struct dentry *parent, size_t *value);
    struct dentry *debugfs_create_bool(const char *name, mode_t mode,
    struct dentry *parent, u32 *value);

    其中,后缀为x8、x16、x32的这三个函数是指debugfs中的数据用十六进制表示。

    创建BLOB文件

    1
    2
    3
    4
    5
    6
    7
    struct debugfs_blob_wrapper {
    void *data;
    unsigned long size;
    };
    struct dentry *debugfs_create_blob(const char *name, mode_t mode,
    struct dentry *parent, struct debugfs_blob_wrapper *blob);

    其它

    1
    2
    3
    4
    5
    struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
    struct dentry *new_dir, const char *new_name);
    struct dentry *debugfs_create_symlink(const char *name,
    struct dentry *parent, const char *target);
  • 相关阅读:
    如何把py文件打包成exe可执行文件
    给大家推荐几款软件
    火狐浏览器报错“support.mozilla.org
    win怎么设置最快捷的下滑关机
    在Ubuntu上安装Chrome Driver和Firefox Driver
    解决pycharm安装包过程出现的问题:module 'pip' has no attribute 'main'
    如何实现windows命令提示符的tab补全?
    在windows下使用cmd命令全速下载百度云文件
    pandas用法大全
    oracle 19c database 静默安装
  • 原文地址:https://www.cnblogs.com/cl1024cl/p/6205698.html
Copyright © 2020-2023  润新知