Last active
August 29, 2015 14:07
-
-
Save chuanwang66/dd640abb40a4784522fa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
debugfs文件系统是一种用于内核调试的虚拟文件系统,内核开发者通过Debugfs和用户空间交换数据。类似的虚拟文件系统还有procfs和sysfs等,这几种虚拟文件系统都并不是实际存储在硬盘上,而是Linux内核运行起来才建立起来。 | |
我们知道/proc文件系统关注的是进程信息;/sysfs关注one-value-per-file策略集,而Debugfs文件系统没有如此多限制,可以是任何内核需要输出的信息。 | |
通常情况下,最常用的内核调试手段是printk。但是printk并不是所有情况都好用,比如打印的数据可能过多,我们真正关心的数据在大量的输出里不是那么一目了然;或者我们在调试时可能需要修改某些内核变量,这种情况下printk就无能为力,而如果为了修改某个值需要重新编译内核或者驱动又过于低效,此时就需要一个临时的文件系统可以把我们需要关心的数据映射到用户空间。在过去,procfs可以实现这个目的,到了2.6时代,新引入的sysfs也同样可以实现。但是无论是procfs还是sysfs,用它们来实现某些debug的需求,似乎偏离了它们创建的本意。比如procfs,其目的是反映进程的状态信息;而sysfs主要用于Linux设备模型。不论是procfs还是sysfs的接口应该保持相对稳定,因为用户态程序很可能会依赖它们。当然,如果我们只是临时借用procfs或者sysfs来作debug之用,在代码发布之前将相关调试代码删除也无不可。但如果相关的调试接口要在相当长一段时间里存在于内核之中,就不太适合放在procfs和sysfs里了。故此,debugfs应运而生。 | |
1. 安装文件系统: | |
Debugfs没有物理设备,默认情况下被挂载在目录/sys/kernel/debug之下,如果发型版里没有自动挂载,可以用如下命令手动完成: | |
mount -t debugfs none /sys/kernel/debug | |
2. 编程使用: | |
#include <linux/debugfs.h> | |
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); //create dir | |
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); //create file, fops操作文件的读写等请求,文件一般用来传递字符串等信息。如果是数字,Debugfs提供以下接口: | |
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_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value); | |
struct dentry *debugfs_create_blob(const char *name, mode_t mode, struct dentry *parent, struct debugfs_blob_wrapper *blob); | |
void debugfs_remove_recursive(struct dentry *dentry); //模块卸载,需要主动删除目录下的文件 | |
下面的例子代码会在debugfs中建立如下目录结构: | |
- mydebug | |
- subdir | |
- c | |
- a | |
- b | |
(1) Makefile | |
EXTRA_CFLAGS := -g | |
obj-m += my_debugfs.o | |
default: | |
make -C /lib/modules/$(shell uname -r)/build/ SUBDIRS=$(shell pwd) modules | |
(2)my_debugfs.c | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/slab.h> | |
#include <linux/debugfs.h> | |
#include <asm/uaccess.h> | |
struct dentry *my_debugfs_root; | |
u8 a = 0; | |
char hello[32] = "Hello world!\n"; | |
struct debugfs_blob_wrapper b; | |
//这里c_open()没有实际用处,因为c_read()和c_write()引用了全局变量hello. | |
//这里,我们也可以换一种写法,在read/write函数中用filp->private_data来引用字符数组hello | |
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; | |
// unsigned long copy_to_user(void __user *to, const void *from, unsigned long n); | |
// to : destination address in user space | |
// from : source address in kernel space | |
// n : number of bytes to copy | |
// returns number of bytes that could not be copied. On success, this will be zero. | |
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, | |
}; | |
static int __init mydebugfs_init(void) | |
{ | |
struct dentry *sub_dir, *r_a, *r_b, *s_c; | |
printk(KERN_INFO "mydebugfs_init\n"); | |
my_debugfs_root = debugfs_create_dir("mydebug", NULL); | |
if (!my_debugfs_root) | |
return -ENOENT; | |
r_a = debugfs_create_u8("a", 0644, my_debugfs_root, &a); | |
if (!r_a) | |
goto Fail; | |
b.data = (void *)hello; | |
b.size = strlen(hello) + 1; | |
r_b = debugfs_create_blob("b", 0644, my_debugfs_root, &b); | |
if (!r_b) | |
goto Fail; | |
sub_dir = debugfs_create_dir("subdir", my_debugfs_root); | |
if (!sub_dir) | |
goto Fail; | |
s_c = debugfs_create_file("c", 0644, sub_dir, NULL, &c_fops); | |
if (!s_c) | |
goto Fail; | |
return 0; | |
Fail: | |
debugfs_remove_recursive(my_debugfs_root); | |
my_debugfs_root = NULL; | |
return -ENOENT; | |
} | |
static void __exit mydebugfs_exit(void) | |
{ | |
printk(KERN_INFO "mydebugfs_exit\n"); | |
debugfs_remove_recursive(my_debugfs_root); | |
return; | |
} | |
module_init(mydebugfs_init); | |
module_exit(mydebugfs_exit); | |
MODULE_LICENSE("GPL"); | |
3. Debugfs内核代码分析 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment