1.简介
debugfs,是一种用于内核调试的虚拟文件系统,内核开发者可以通过debugfs和用户空间交换数据。虚拟文件系统还有procfs和sysfs等,虚拟文件系统都并不实际存储在硬盘上,而建立在内存中。
我们最常用的内核调试手段是printk。但printk并不是所有情况都好用,比如打印的数据可能过多,我们真正关心的数据在大量的输出里不是那么一目了然;或者我们在调试时可能需要修改某些内核变量,这种情况下printk就无能为力,而如果为了修改某个值重新编译内核或者驱动又过于低效,此时就需要一个临时的文件系统可以把我们需要关心的数据映射到用户空间。
在过去,procfs可以实现这个目的,到了2.6时代,新引入的sysfs也同样可以实现,但不论是procfs或是sysfs,用它们来实现某些debug的需求,似乎偏离了它们创建的本意。比如procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs或是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。当然,如果我们只是临时借用procfs或者sysfs来作debug之用,在代码发布之前将相关调试代码删除也无不可。但如果相关的调试借口要在相当长的一段时间内存在于内核之中,就不太适合放在procfs和sysfs里了。故此,debugfs应运而生。
2.配置内核
配置CONFIG_DEBUG_FS=y让内核支持debugfs,也可以在menuconfig中指定:
Kernel hacking --->
[*] Debug Filesystem
内核默认会将debugfs挂载在/sys/kernel/debug目录下,也可以指定挂载目录:mount -t debugfs none /mnt
3.创建debugfs
1. 创建根目录
/* 第一个参数是目录的名称,
* 第二个参数用来指定这个目录的上级目录,如果是NULL,则表示是放在debugfs的根目录里。
*/
my_debugfs_root = debugfs_create_dir("test_debug", NULL);
2.创建调试文件
static int test_open(structinode *inode, structfile *filp)
{
filp->private_data = inode->i_private;
return0;
}
static ssize_t test_read(structfile *filp, char__user *buffer,
size_tcount, loff_t *ppos)
{
if(*ppos >= 32)
return0;
if(*ppos + count > 32)
count = 32 - *ppos;
if(copy_to_user(buffer, hello + *ppos, count))
return-EFAULT;
*ppos += count;
return count;
}
static ssize_t test_write(structfile *filp, constchar __user *buffer,
size_tcount, loff_t *ppos)
{
if(*ppos >= 32)
return0;
if(*ppos + count > 32)
count = 32 - *ppos;
if(copy_from_user(hello + *ppos, buffer, count))
return-EFAULT;
*ppos += count;
returncount;
}
structfile_operations teat_fops = {
.owner = THIS_MODULE,
.open = test_open,
.read = test_read,
.write = test_write,
};
/* 第一个参数为文件名,第二个参数为文件权限属性,第三个文件参数为父目录
* 第四个参数指向驱动程序分配的数据,第五个参数指向驱动分配的file_operations结构体
*/
debugfs_create_file("test", 0644, test_debug, NULL, &test_fops);
4.移除调试文件
驱动退出时,我们要记得在module_exit中释放创建的数据,有两种方法可以移除创建的dentry:
1. debugfs_remove_recursive(test_debug); //debugfs_remove_recursive可以递归地移除每个分配的dentry
2. 如果您想一个一个手动的移除,也可以直接调用debugfs_remove。
5.常用函数
1.创建和移除目录和文件
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);
2.创建单值文件
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);
/* x8、x16、x32三个函数是指debugfs中的数据用十六进制表示 */
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);
3.创建BLOB文件
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);