Linux内核debugfs
debugfs
虚拟文件系统是一种内核空间与用户空间的接口,基于libfs库实现,专用于开发人员调试,便于向用户空间导出内核空间数据。
内核开发者经常需要向用户空间应用输出一些调试信息,在稳定的系统中可能根本不需要这些调试信息。 但是在开发过程中,为了搞清楚内核的行为,调试信息非常必要。 printk可能是用的最多的,但它并不是最好的,调试信息只是在开发中用于调试,而printk将一直输出,因此开发完毕后需要清除不必要的printk语句。 另外如果开发者希望用户空间应用能够改变内核行为时,printk就无法实现。 因此,需要一种新的机制,那只有在需要的时候使用,它在需要时通过在一个虚拟文件系统中创建一个或多个文件来向用户空间应用提供调试信息。
为了使得开发者更加容易使用这样的机制,Greg Kroah-Hartman开发了debugfs(在2.6.11中第一次引入),它是一个虚拟文件系统,专门用于输出调试信息,该文件系统非常小,很容易使用,可以在配置内核时选择是否构件到内核中,在不选择它的情况下,使用它提供的API的内核部分不需要做任何改动。
挂载debugfs文件系统
要使用debugfs,需要在内核编译配置中配置
CONFIG_DEBUG_FS=y
选项,一般的发行版都会默认编译进了内核。通过下面命令查看
1
cat /boot/config-`uname -r` | grep CONFIG_DEBUG_FS
/sys/kernel/debug
),也可手动挂载到其它位置:
1
2mkdir /debugfs
mount -t debugfs none /debugfs
创建目录和文件
使用debugfs的开发者首先需要在文件系统中创建一个目录,下面函数用于在debugfs文件系统下创建一个目录:
1
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
name
是要创建的目录名, +
parent
指定创建目录的父目录的
dentry
,如果为NULL,目录将创建在debugfs文件系统的根目录下。如果返回为-ENODEV,表示内核没有把debugfs编译到其中,如果返回为NULL,表示其他类型的创建失败,如果创建目录成功,返回指向该目录对应的dentry条目的指针。
下面函数用于在debugfs文件系统中创建一个文件: 1
2
3struct dentry *debugfs_create_file(const char *name, mode_t mode,
struct dentry *parent, void *data,
struct file_operations *fops);file_operations
结构指针。
导出基本的数据类型变量
当然,在一些情况下,开发者可能仅需要使用用户应用可以控制的变量来调试。
debugfs可以将内核中基本整数类型的变量导出为单个文件,在用户空间中可以直接对其读写(如使用cat、echo命令),只要权限允许即可。
支持的类型有:u8
, u16
, u32
,
u64
, size_t
和bool
。 其中
bool
类型在内核中要定义为 u32
类型,在用户空间中对应的文件内容则显示为 Y
或N
。
debugfs提供的API为: 1
2
3
4
5
6
7
8struct 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_bool(const char *name, mode_t mode,
struct dentry *parent, u32 *value);
示例代码如下: 1
2
3
4
5static 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变量
销毁目录和文件
当内核模块卸载时,Debugfs并不会自动清除该模块创建的目录或文件,因此对于创建的每一个文件或目录,开发者必须调用下面函数清除:
1
void debugfs_remove(struct dentry *dentry);
debugfs_remove_recursive
递归删除整个目录。 1
void debugfs_remove_recursive(struct dentry *dentry);