内核开发者常常需求向用户空间运用输出一些调试信息,在安稳的体系中或许底子不需求这些调试信息,可是在开发过程中,为了搞清楚内核的行为,调试信息十分必要,printk或许是用的最多的,但它并不是最好的,调试信息仅仅在开发中用于调试,而printk将一向输出,因而开发结束后需求铲除不必要 的printk句子,别的假如开发者期望用户空间运用可以改动内核行为时,printk就无法完结。因而,需求一种新的机制,那只有在需求的时分运用,它在需求时经过在一个虚拟文件体系中创立一个或多个文件来向用户空间运用供给调试信息。
有几种办法可以完结上述要求:
(1)运用procfs,在/proc创立文件输出调试信息,可是procfs关于大于一个内存页(关于x86是4K)的输出比较费事,而且速度慢,有时回呈现一些意想不到的问题。
(2)运用sysfs(2.6内核引进的新的虚拟文件体系),在许多情况下,调试信息可以寄存在那里,可是sysfs首要用于体系管理,它期望每一个文件对应内核的一个变量,假如运用它输出杂乱的数据结构或调试信息是十分困难的。
(3)运用libfs创立一个新的文件体系,该办法极端灵敏,开发者可以为新文件体系设置一些规矩,运用libfs使得创立新文件体系愈加简略,可是依然超出了一个开发者的幻想。
(4)为了使得开发者愈加简单运用这样的机制,Greg Kroah-Hartman开发了debugfs(在2.6.11中第一次引进),它是一个虚拟文件体系,专门用于输出调试信息,该文件体系十分小,很简单运用,可以在装备内核时挑选是否构件到内核中,在不挑选它的情况下,运用它供给的API的内核部分不需求做任何改动。
运用debugfs的开发者首要需求在文件体系中创立一个目录,下面函数用于在debugfs文件体系下创立一个目录:
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
参数name是要创立的目录名,参数parent指定创立目录的父目录的dentry,假如为NULL,目录将创立在debugfs文件体系的根目录下。假如回来为-ENODEV,表明内核没有把debugfs编译到其间,假如回来为NULL,表明其他类型的创立失利,假如创立目录成功,回来指向该 目录对应的dentry条目的指针。
下面函数用于在debugfs文件体系中创立一个文件:
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent,
void *data, struct file_operations *fops);
参数name指定要创立的文件名,参数mode指定该文件的拜访答应,参数parent指向该文件地点目录,参数data为该文件特定的一些数据, 参数fops为完结在该文件进步行文件操作的fiel_operaTIons结构指针,在许多情况下,由seq_file供给的文件操作完结就足够了,因而运用debugfs很简单,当然,在一些情况下,开发者或许仅需求运用用户运用可以操控的变量来调试,debugfs也供给了4个这样的API便利开发者运用:
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_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value);
参数name和mode指定文件名和拜访答应,参数value为需求让用户运用操控的内核变量指针。
当内核模块卸载时,Debugfs并不会主动铲除该模块创立的目录或文件,因而关于创立的每一个文件或目录,开发者有必要调用下面函数铲除:
void debugfs_remove(struct dentry *dentry);
参数dentry为上面创立文件和目录的函数回来的dentry指针。
在下面给出了一个运用debufs的示例模块debugfs_exam.c,为了确保该模块正确运转,有必要让内核支撑debugfs, debugfs是一个调试功用,因而它坐落主菜单Kernel hacking,而且有必要挑选Kernel debugging选项才干挑选,它的选项名称为Debug Filesystem。为了在用户态运用debugfs,用户有必要mount它,下面是在作者体系上的运用输出:
$ mkdir -p /debugfs
$ mount -t debugfs debugfs /debugfs
$ insmod 。/debugfs_exam.ko
$ ls /debugfs
debugfs-exam
$ ls /debugfs/debugfs-exam
u8_var u16_var u32_var bool_var
$ cd /debugfs/debugfs-exam
$ cat u8_var
0
$ echo 200 》 u8_var
$ cat u8_var
200
$ cat bool_var
N
$ echo 1 》 bool_var
$ cat bool_var
Y
//kernel module: debugfs_exam.c
#include 《linux/config.h》
#include 《linux/module.h》
#include 《linux/debugfs.h》
#include 《linux/types.h》
/*dentry:目录项,是Linux文件体系中某个索引节点(inode)的链接。这个索引节点可以是文件,也可以是目录。
Linux用数据结构dentry来描绘fs中和某个文件索引节点相链接的一个目录项(能是文件,也能是目录)。
(1)未运用(unused)状况:该dentry目标的引证计数d_count的值为0,但其d_inode指针依然指向相关
的的索引节点。该目录项依然包括有用的信息,仅仅当时没有人引证他。这种dentry目标在收回内存时或许会被开释。
(2)正在运用(inuse)状况:处于该状况下的dentry目标的引证计数d_count大于0,且其d_inode指向相关
的inode目标。这种dentry目标不能被开释。
(3)负(negaTIve)状况:和目录项相关的inode目标不复存在(相应的磁盘索引节点或许已被删去),dentry
目标的d_inode指针为NULL。但这种dentry目标依然保存在dcache中,以便后续对同一文件名的查找可以快速完结。
这种dentry目标在收回内存时将首要被开释。
*/
staTIc struct dentry *root_entry, *u8_entry, *u16_entry, *u32_entry, *bool_entry;
staTIc u8 var8;
static u16 var16;
static u32 var32;
static u32 varbool;
static int __init exam_debugfs_init(void)
{
root_entry = debugfs_create_dir(“debugfs-exam”, NULL);
if (!root_entry) {
printk(“Fail to create proc dir: debugfs-exam\n”);
return 1;
}
u8_entry = debugfs_create_u8(“u8-var”, 0644, root_entry, &var8);
u16_entry = debugfs_create_u16(“u16-var”, 0644, root_entry, &var16);
u32_entry = debugfs_create_u32(“u32-var”, 0644, root_entry, &var32);
bool_entry = debugfs_create_bool(“bool-var”, 0644, root_entry, &varbool);
return 0;
}
static void __exit exam_debugfs_exit(void)
{
debugfs_remove(u8_entry);
debugfs_remove(u16_entry);
debugfs_remove(u32_entry);
debugfs_remove(bool_entry);
debugfs_remove(root_entry);
}
module_init(exam_debugfs_init);
module_exit(exam_debugfs_exit);
MODULE_LICENSE(“GPL”);