debugfs
1. 简介
类似sysfs、procfs
,debugfs
也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据需求对指定的变量进行导出并提供读写接口。debugfs又是一个Linux中 everything is a file 哲学的体现,通过VFS实现了对驱动的控制。可以通过以下命令,来挂载debugfs到指定目录。
Debugfs
其存在的主要意义是为了内核开发者向用户空间传递更多有用的信息,与proc不同,proc只提供进程相关的信息;同时也与sysfs不同,sysfs对每个文件都要求一定的规则,而Debugfs没有任何的规则。
简而言之,Debugfs是一种用于内核调试的虚拟文件系统。
用途:将内核程序中的变量以文件的形式直观的展现出来,并可以直接通过文件操作来读取或修改内核变量的值,便于开发调试
2. 食用方式
1. 内核使能Debudfs
在menuconfig
中使能DEBUG_FS = y
2.挂载命令
mount -t debugfs none /sys/kernel/debug
3.内核接口
1. API接口
- 想要使用Debugfs功能,首先要做的就是要包含
<linux/debugfs.h>
头文件 - 使用
debugfs_create_dir
接口,创建一个文件夹,用于保存debugfs所操作的文件 - 使用
debugfs_create_file
接口,创建多个文件进行操作
2. API介绍
debugfs_create_dir
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
参数 | 作用 | 备注 |
---|---|---|
name | 文件夹名称 | |
parent | 父目录 | 如果为NULL,则在root根目录下 |
debugfs_create_file
struct dentry *debugfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops);
参数 | 作用 | 备注 |
---|---|---|
name | 文件夹名称 | |
mode | 文件访问权限 | 可以是整型(比如0644)也可以使用内核的宏 |
parent | 父目录,用于保存该文件 | 如果为空则该文件的父目录为根目录 |
data | 文件操作的私有数据 | inode的i_private字段指向这个结构 |
fops | 文件的自定义操作 | 可以自定义所有操作接口,也可以使用宏DEFINE_SIMPLE_ATTRIBUTE 指定读写操作即可 |
DEFINE_SIMPLE_ATTRIBUTE宏:
// get : 读操作
// set : 写操作
// fmt : 用于指定 get 和 set 函数的输入输出格式。
//例如,它可以定义一个整数、浮点数或字符串的格式,以便在 sysfs 接口中正确显示或解析值。
#define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt) \
static int __fops ## _open(struct inode *inode, struct file *file) \
{ \
__simple_attr_check_format(__fmt, 0ull); \
return simple_attr_open(inode, file, __get, __set, __fmt); \
} \
static const struct file_operations __fops = { \
.owner = THIS_MODULE, \
.open = __fops ## _open, \
.release = simple_attr_release, \
.read = simple_attr_read, \
.write = simple_attr_write, \
.llseek = generic_file_llseek, \
}
debugfs_create_u8
void debugfs_create_u8(const char *name, umode_t mode,struct dentry *parent, u8 *value);
参数 | 作用 | 备注 |
---|---|---|
name | 文件名 | 一般以变量名来命名,方便调试 |
mode | 文件权限 | |
parent | 父目录 | |
value | 变量 | 变量的值会被存在文件内 |
其他变量类型的接口:👇
//创建十进制的无符号文件
void debugfs_create_u8(const char *name, umode_t mode,
struct dentry *parent, u8 *value);
void debugfs_create_u16(const char *name, umode_t mode,
struct dentry *parent, u16 *value);
void debugfs_create_u32(const char *name, umode_t mode,
struct dentry *parent, u32 *value);
void debugfs_create_u64(const char *name, umode_t mode,
struct dentry *parent, u64 *value);
//创建十六进制的无符号文件
void debugfs_create_x8(const char *name, umode_t mode,
struct dentry *parent, u8 *value);
void debugfs_create_x16(const char *name, umode_t mode,
struct dentry *parent, u16 *value);
void debugfs_create_x32(const char *name, umode_t mode,
struct dentry *parent, u32 *value);
void debugfs_create_x64(const char *name, umode_t mode,
struct dentry *parent, u64 *value);
//创建一个size_t类型的文件
void debugfs_create_size_t(const char *name, umode_t mode,struct dentry *parent, size_t *value);
//创建一个unsigned long类型的文件
struct dentry *debugfs_create_ulong(const char *name, umode_t mode,struct dentry *parent,unsigned long *value);
//创建一个十六进制的unsigned long类型的文件
void debugfs_create_xul(const char *name, umode_t mode,struct dentry *parent, unsigned long *value);
// 布尔型
void debugfs_create_bool(const char *name, umode_t mode,
struct dentry *parent, bool *value);
Deme one
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
static struct dentry *dir = NULL;
static unsigned int debugfs_hello;
static u32 sum = 0;
static int add_write(void *data, u64 value)
{
sum += value;
return 0;
}
// 文件操作变量名,get读操作,set写操作,将读写操作的返回值以字符串格式化的形式读出或写入文件内部
DEFINE_SIMPLE_ATTRIBUTE(add_ops, NULL, add_write, "%llu\n");
static __init int hello_init(void)
{
struct dentry *tmp_dir = NULL;
/* create /sys/kernel/debug/debugfs_hello/ directory */
dir = debugfs_create_dir("debugfs_hello", NULL);
if (!dir) {
printk(KERN_ALERT "debugfs_create_dir failed\n");
return -1;
}
/* create /sys/kernel/debug/debugfs_hello/hello value, mode: rw*/
tmp_dir = debugfs_create_u32("hello", 00666, dir, &debugfs_hello);
if (!tmp_dir) {
printk(KERN_ALERT "debugfs_create_u32 failed\n");
return -1;
}
/* create /sys/kernel/debug/debugfs_hello/add value, mode: w*/
tmp_dir = debugfs_create_file("add", 0222, dir, NULL, &add_ops);
if (!tmp_dir) {
printk(KERN_ALERT "debugfs_create_file failed\n");
return -1;
}
/* create /sys/kernel/debug/debugfs_hello/sum value, mode: r*/
tmp_dir = debugfs_create_u32("sum", 0444, dir, &sum);
if (!tmp_dir) {
printk(KERN_ALERT "debugfs_create_u32 failed\n");
return -1;
}
return 0;
}
static void __exit hello_exit(void)
{
printk(KERN_INFO "Exit debugfs_hello module\n");
debugfs_remove_recursive(dir);
dir = NULL;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
Demo TWO
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/errno.h>
#include <linux/dcache.h>
#include <linux/types.h>
static char zen_buf[512] = "hello\n";
static struct dentry *zen_dir;
static int zen_open(struct inode *inode, struct file *filp)
{
printk("zen open\n");
filp->private_data = inode->i_private;
return 0;
}
ssize_t zen_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
{
int retval = 0;
if ((*offp + count) > 512)
count = 512 - *offp;
printk("read request: count:%u, offset:%u\n", count, *offp);
if (copy_to_user(buf, zen_buf+*offp, count)) {
printk("copy to user failed, count:%ld\n", count);
retval = -EFAULT;
goto out;
}
*offp += count;
retval = count;
out:
return retval;
}
ssize_t zen_write(struct file *filp, const char __user *buff, size_t count, loff_t *offp)
{
int retval;
printk("write request: count:%u, offset:%u\n", count, *offp);
if (*offp > 512)
return 0;
if (*offp + count > 512)
count = 512 - *offp;
if (copy_from_user(zen_buf+*offp, buff, count)) {
printk("copy from user failed, count:%ld\n", count);
retval = -EFAULT;
goto out;
}
*offp += count;
retval = count;
out:
return retval;
}
struct file_operations my_fops = {
.owner = THIS_MODULE,
.read = zen_read,
.write = zen_write,
.open = zen_open,
};
static int __init debugfs_init(void)
{
printk("INIT MODULE\n");
zen_dir = debugfs_create_dir("zen_dir4", NULL);
if (!zen_dir) {
printk("zen_dir4 is null\n");
goto fail;
}
static struct dentry *sub_zen_dir;
sub_zen_dir = debugfs_create_dir("sub_zen", zen_dir);
if (!sub_zen_dir) {
printk("sub zen dir is null\n");
goto fail;
}
struct dentry *filent = debugfs_create_file("zen", 0644, sub_zen_dir, NULL, &my_fops);
if (!filent) {
printk("zen file is null\n");
goto fail;
}
printk("INIT SUCCESS\n");
return 0;
fail:
//return -ENOENT;
return -1;
}
static void __exit debugfs_exit(void)
{
printk("exit module\n");
debugfs_remove_recursive(zen_dir);
printk("exit success\n");
}
module_init(debugfs_init);
module_exit(debugfs_exit);
MODULE_LICENSE("GPL");