DebugFS,顾名思义,是一种用于内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据。(类似的虚拟文件系统还有procfs和sysfs等!procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。)。虚拟文件系统都并不实际存储在硬盘上,而是Linux内核运行起来后才建立起来。
默认情况下,debugfs会被挂载在目录/sys/kernel/debug之下,如果您的发行版里没有自动挂载,可以用如下命令手动完成:
# mount -t debugfs none /your/debugfs/dir |
这个实作会在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); |