类似sysfs、procfs,debugfs 也是一种内存文件系统。不过不同于sysfs一个kobject对应一个文件,procfs和进程相关的特性,debugfs的灵活度很大,可以根据
需求对指定的变量进行导出并提供读写接口。debugfs又是一个Linux中 everything is a file 哲学的体现,通过VFS实现了对驱动的控制。可以通过以下命令,来
挂载debugfs到指定目录。
mount -t debugfs none /sys/kernel/debug
支持的读写类型
debugfs支持比较丰富的数据类型,如下所示。
使用方式1、创建目录和文件
使用 debugfs_create_dir 创建一个目录,如果parent为NULL,则默认其父目录为debugfs的根目录。函数的返回值为NULL表示目录创建成功。
debugfs_create_file和debugfs_create_file_size都用来创建文件,不同的是debugfs_create_file_size可以通过file_size字段指定一个初始的大小。
name:文件名
mode:文件权限可以是整型(比如0644)也可以使用内核的宏
parent:父目录,如果为空则该文件的父目录为根目录
data:inode的i_private字段指向这个结构
fops:表示该文件的自定义操作,需要注意的是在我实际测试中open函数可能是必须要实现的,否则在使用echo命令的时候会报以下的错误
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
struct dentry *debugfs_create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops);
void debugfs_create_file_size(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops,
loff_t file_size);
2、创建无符号整型文件
//创建十进制的无符号文件
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);
3、布尔类型文件
void debugfs_create_bool(const char *name, umode_t mode,
struct dentry *parent, bool *value);
读布尔文件会显示Y或者N,写该文件时,只接受(Y, N, y, n, 0, 1)等值,其他值都只会被简单的忽略。
4、原子类型
void debugfs_create_atomic_t(const char *name, umode_t mode,
struct dentry *parent, atomic_t *value)
5、blob类型
使用debugfs_create_blob创建一个blob类型的文件,调用该函数前,我们需要在debugfs_blob_wrapper的data字段指定要展示的内容,size表示data长度。
需要注意的是blob类型的文件是只读的
struct debugfs_blob_wrapper {
void *data;
unsigned long size;
};
struct dentry *debugfs_create_blob(const char *name, umode_t mode,
struct dentry *parent,
struct debugfs_blob_wrapper *blob);
6、寄存器类型
使用 debugfs_reg32 表示一个寄存器内容,name表示文件名,offset表示相对于基地址的偏移。debugfs_regset32 表示一组寄存器文件,nregs:寄存器文件个数 base:io基地址
struct debugfs_reg32 {
char *name;
unsigned long offset;
};
struct debugfs_regset32 {
const struct debugfs_reg32 *regs;
int nregs;
void __iomem *base;
struct device *dev; /* Optional device for Runtime PM */
};
debugfs_create_regset32(const char *name, umode_t mode,
struct dentry *parent,
struct debugfs_regset32 *regset);
void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
int nregs, void __iomem *base, char *prefix);
踩坑
1、debugfs的API的都是GPL的,因此在自己的模块必须要指定协议为GPL
2、使用echo写文件的话,open函数是必须的。
代码实例#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");