内核交互--debugfs_转
DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。类似的虚拟文件系统还有procfs和sysfs等,这几种虚拟文件系统都并不实际存储在硬盘上,而是Linux内核运行起来后才建立起来。
通常情况下,最常用的内核调试手段是printk。但printk并不是所有情况都好用,比如打印的数据可能过多,我们真正关心的数据在大量的输出里不是那么一目了然;或者我们在调试时可能需要修改某些内核变量,这种情况下printk就无能为力,而如果为了修改某个值重新编译内核或者驱动又过于低效,此时就需要一个临时的文件系统可以把我们需要关心的数据映射到用户空间。在过去,procfs可以实现这个目的,到了2.6时代,新引入的sysfs也同样可以实现,但不论是procfs或是sysfs,用它们来实现某些debug的需求,似乎偏离了它们创建的本意。比如procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。当然,如果我们只是临时借用procfs或者sysfs来作debug之用,在代码发布之前将相关调试代码删除也无不可。但如果相关的调试借口要在相当长的一段时间内存在于内核之中,就不太适合放在procfs和sysfs里了。故此,debugfs应运而生。
默认情况下,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通过自定义的文件操作同时实现了读和写。
注:debugfs_create_file()中参数data为私有数据,之后创建文件时会传递给inode->i_private,在file open时可以将inode->i_private传递给file->private_data。
|
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, 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); |
内核交互--debugfs_转的更多相关文章
- ifconfig源码分析之与内核交互数据
<ifconfig源码分析之与内核交互数据>本文档的Copyleft归rosetta所有,使用GPL发布,可以自由拷贝.转载,转载时请保持文档的完整性.参考资料:<Linux设备驱动 ...
- Python IO内核交互了解
注:Unix \ Linux 环境下的network IO 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方).操作系 ...
- 内核交互--sysfs
文档介绍:http://lxr.linux.no/linux+v2.6.37/Documentation/filesystems/sysfs.txt The sysfs Filesystem Sysf ...
- 内核交互--procfs
文档介绍:http://lxr.linux.no/linux+v2.6.37/Documentation/filesystems/proc.txt以下内容抄录linux设备驱动开发详解-宋宝华在/pr ...
- linux内核交互,设备驱动控制管理接口
1,ioctl preface--starting point ,format,mount volume,in addition to the above file system -- allows ...
- 深入理解Linux网络技术内幕——用户空间与内核空间交互
概述: 内核空间与用户空间经常需要进行交互.举个例子:当用户空间使用一些配置命令如ifconfig或route时,内核处理程序就要响应这些处理请求. 用户空间与内核有多种交互方式,最常 ...
- Linux 用户态与内核态的交互【转载】
Linux 用户态与内核态的交互 在 Linux 2.4 版以后版本的内核中,几乎全部的中断过程与用户态进程的通信都是使用 netlink 套接字实现的,例如iprote2网络管理工具,它与内核的交 ...
- 《Linux内核设计与实现》读书笔记(十八)- 内核调试
内核调试的难点在于它不能像用户态程序调试那样打断点,随时暂停查看各个变量的状态. 也不能像用户态程序那样崩溃后迅速的重启,恢复初始状态. 用户态程序和内核交互,用户态程序的各种状态,错误等可以由内核来 ...
- 戴文的Linux内核专题:02源代码
转自Linux中国 在下载并解压内核源代码后,用户可以看到许多文件夹和文件.尝试去找一个特定的文件或许是一个挑战.谢天谢地,源代码以一个特定的方式组织的.这使开发者能够轻松找到任何文件或者内核的一部分 ...
随机推荐
- sqlserver用于统计表索引情况
/*eg: --调用该过程实例 --1 创建临时表 IF OBJECT_ID('tempdb..#index_sql_text') IS NOT NULL DROP TABLE #index_sql_ ...
- Modify Headers模拟不同地域进行网页测试
今天要简单讲一下Modify Headers这个Firefox插件,记录一下我是怎么使用它的. Modify Headers: https://addons.mozilla.org/zh-CN/fir ...
- JavaScript获取table中某一列的值的方法
1.实现源码 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www. ...
- solr6.6 高级搜索Facet
1.介绍 facet分面查询是solr中以导航为目的的查询,在用户查询的结果上根据分类增加了count信息,然后用户根据count信息做进一步实现渐进式精确搜索. 什么字段适合用facet呢? fa ...
- OS中处理机调度模型和调度算法
OS中处理机调度模型和调度算法 调度层次 1.1. 高级调度(长程调度,作业调度) 功能:依据某种算法.把在外存队列上处于后备队列的那些作业调入内存.以作业为操做对象. 作业:比程序更为广泛的概念,不 ...
- asp.net购物车,订单以及模拟支付宝支付(二)---订单表
购物车准备完毕之后,就要着手订单表的设计了 表结构如下: T_Orders T_OrderBooks 为什么这里要分为两个表? 仔细想想,现实生活中的发票 特地去网上找了一张,不是很清晰 但是,正常人 ...
- 【转】angular中$parse详解教程
原文: https://yq.aliyun.com/ziliao/40516 ------------------------------------------------------------- ...
- stat,查看文件属性
shell命令,查看文件详细属性 别再跟我回答ls -l了
- android 开发者的个人博客集
1. http://stormzhang.com/posts.html //不少的好的工具与建议
- maven 插件之 AutoConfig 工具使用笔记
AutoConfig 是一款 maven 插件,主要用于 Maven 项目打包使用.在我们的工作中,会将自己写的代码打成 jar 包或者 war 包发布到各种环境上.一般地,不用的环境所使用的数据库. ...