插件窝 干货文章 Linux驱动 | debugfs接口创建

Linux驱动 | debugfs接口创建

debugfs debug struct 文件 931    来源:    2025-04-14

Linux驱动中的debugfs接口创建

debugfs是Linux内核提供的一个用于调试的虚拟文件系统,它允许驱动开发人员在内核空间和用户空间之间快速交换调试信息。下面我将详细介绍如何在Linux驱动中创建和使用debugfs接口。

1. debugfs基础

1.1 debugfs简介

  • 专为内核调试设计的虚拟文件系统
  • 挂载在/sys/kernel/debug/目录下
  • 提供简单的API创建和操作调试文件

1.2 基本使用步骤

  1. 挂载debugfs文件系统
  2. 创建debugfs目录和文件
  3. 实现文件操作函数
  4. 在模块退出时清理debugfs文件

2. debugfs API

2.1 头文件

#include <linux/debugfs.h>

2.2 主要API函数

创建和删除目录

struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
void debugfs_remove(struct dentry *dentry);

创建各种类型的文件

// 创建普通文件
struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);

// 创建布尔文件
struct dentry *debugfs_create_bool(const char *name, umode_t mode,
                                   struct dentry *parent, u32 *value);

// 创建X32文件(32位无符号整型)
struct dentry *debugfs_create_x32(const char *name, umode_t mode,
                                  struct dentry *parent, u32 *value);

// 创建原子变量文件
struct dentry *debugfs_create_atomic_t(const char *name, umode_t mode,
                                       struct dentry *parent,
                                       atomic_t *value);

// 创建blob文件(二进制大对象)
struct dentry *debugfs_create_blob(const char *name, umode_t mode,
                                   struct dentry *parent,
                                   struct debugfs_blob_wrapper *blob);

3. 完整示例代码

3.1 简单示例

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>

static struct dentry *dir = NULL;
static u32 debug_value = 0;

static ssize_t debug_read(struct file *file, char __user *user_buf,
                          size_t count, loff_t *ppos)
{
    char buf[32];
    int len;

    len = snprintf(buf, sizeof(buf), "%u\n", debug_value);
    return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t debug_write(struct file *file, const char __user *user_buf,
                           size_t count, loff_t *ppos)
{
    char buf[32];
    unsigned long val;

    if (count >= sizeof(buf))
        return -EINVAL;

    if (copy_from_user(buf, user_buf, count))
        return -EFAULT;

    buf[count] = '\0';
    if (kstrtoul(buf, 10, &val))
        return -EINVAL;

    debug_value = val;
    return count;
}

static const struct file_operations debug_fops = {
    .read = debug_read,
    .write = debug_write,
};

static int __init debug_init(void)
{
    // 在debugfs根目录下创建我们的目录
    dir = debugfs_create_dir("my_debug", NULL);
    if (!dir) {
        pr_err("Failed to create debugfs directory\n");
        return -ENOMEM;
    }

    // 在目录中创建一个可读写文件
    debugfs_create_file("value", 0644, dir, NULL, &debug_fops);

    // 创建一个x32类型的文件
    debugfs_create_x32("xvalue", 0644, dir, &debug_value);

    pr_info("Debugfs interface initialized\n");
    return 0;
}

static void __exit debug_exit(void)
{
    // 递归删除整个目录
    debugfs_remove_recursive(dir);
    pr_info("Debugfs interface removed\n");
}

module_init(debug_init);
module_exit(debug_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Debugfs example module");

3.2 更复杂的示例(包含多种文件类型)

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/debugfs.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/atomic.h>

static struct dentry *dir = NULL;
static u32 debug_value = 0;
static bool debug_flag = false;
static atomic_t debug_counter = ATOMIC_INIT(0);

// 二进制数据示例
static char debug_blob_data[] = "This is a blob data example";
static struct debugfs_blob_wrapper blob_wrapper = {
    .data = debug_blob_data,
    .size = sizeof(debug_blob_data),
};

static ssize_t debug_read(struct file *file, char __user *user_buf,
                          size_t count, loff_t *ppos)
{
    char buf[32];
    int len;

    len = snprintf(buf, sizeof(buf), "%u\n", debug_value);
    return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}

static ssize_t debug_write(struct file *file, const char __user *user_buf,
                           size_t count, loff_t *ppos)
{
    char buf[32];
    unsigned long val;

    if (count >= sizeof(buf))
        return -EINVAL;

    if (copy_from_user(buf, user_buf, count))
        return -EFAULT;

    buf[count] = '\0';
    if (kstrtoul(buf, 10, &val))
        return -EINVAL;

    debug_value = val;
    return count;
}

static const struct file_operations debug_fops = {
    .read = debug_read,
    .write = debug_write,
};

static int __init debug_init(void)
{
    // 在debugfs根目录下创建我们的目录
    dir = debugfs_create_dir("complex_debug", NULL);
    if (!dir) {
        pr_err("Failed to create debugfs directory\n");
        return -ENOMEM;
    }

    // 创建各种类型的debugfs文件
    debugfs_create_file("value", 0644, dir, NULL, &debug_fops);
    debugfs_create_x32("xvalue", 0644, dir, &debug_value);
    debugfs_create_bool("flag", 0644, dir, &debug_flag);
    debugfs_create_atomic_t("counter", 0644, dir, &debug_counter);
    debugfs_create_blob("blob", 0444, dir, &blob_wrapper);

    pr_info("Complex debugfs interface initialized\n");
    return 0;
}

static void __exit debug_exit(void)
{
    debugfs_remove_recursive(dir);
    pr_info("Complex debugfs interface removed\n");
}

module_init(debug_init);
module_exit(debug_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("Complex debugfs example module");

4. 使用注意事项

  1. 权限管理:

    • 使用适当的文件权限模式(如0644)
    • 生产环境中应考虑移除debugfs接口或限制访问
  2. 错误处理:

    • 检查debugfs_create_*函数的返回值
    • 处理内存不足等错误情况
  3. 并发控制:

    • 在多核系统中访问共享数据时使用适当的锁机制
    • 考虑使用atomic_t等原子操作
  4. 清理工作:

    • 模块退出时必须移除所有创建的debugfs条目
    • 使用debugfs_remove_recursive()可以方便地删除整个目录树
  5. 性能考虑:

    • debugfs操作不应影响系统关键路径的性能
    • 避免在频繁调用的函数中执行debugfs操作

5. 实际应用场景

  1. 驱动状态监控:

    • 实时查看设备寄存器值
    • 监控DMA缓冲区状态
  2. 调试信息输出:

    • 记录驱动内部状态变化
    • 输出性能统计信息
  3. 参数动态调整:

    • 运行时修改调试级别
    • 调整驱动行为参数
  4. 故障诊断:

    • 提供诊断信息收集接口
    • 支持触发特定测试场景

debugfs为Linux驱动开发提供了强大而灵活的调试工具,合理使用可以显著提高驱动开发和调试效率。