当前位置: 首页 > article >正文

调试文件系统(DebugFS )

Debugfs 是内核开发人员向用户空间提供信息的一种简单方法。与仅用于存储进程信息的 /proc 或具有严格“每个文件一个值”规则的 sysfs 不同,debugfs 根本没有任何规则。开发人员可以将任何他们想要的信息放在那里。debugfs 文件系统也不打算用作用户空间的稳定 ABI;理论上,对导出到那里的文件没有稳定性限制。然而,现实世界并不总是如此简单,即使是 debugfs 接口,在设计时也最好考虑到它们需要永远维护。

Debugfs 通常使用以下命令安装:

mount -t debugfs none /sys/kernel/debug

(或等效的 /etc/fstab 行)。默认情况下,只有 root 用户才能访问 debugfs 根目录。要更改对树的访问权限,可以使用“uid”、“gid”和“mode”挂载选项。

请注意,debugfs API 仅以 GPL 形式导出到模块。

使用 debugfs 的代码应该包含<linux/debugfs.h>。然后,第一件事是创建至少一个目录来保存一组 debugfs 文件:

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

如果成功,此调用将在指定的父目录下创建一个名为 name 的目录。如果 parent 为 NULL,则将在 debugfs 根目录中创建目录。成功时,返回值是一个 struct dentry 指针,可用于在目录中创建文件(并在最后清理它)。ERR_PTR(-ERROR) 返回值表示出现问题。如果返回 ERR_PTR(-ENODEV),则表明内核是在没有 debugfs 支持的情况下构建的,并且下面描述的所有函数都将不起作用。

在 debugfs 目录中创建文件的最常用方法是:

struct dentry *debugfs_create_file(const char *name, umode_t mode,
                                   struct dentry *parent, void *data,
                                   const struct file_operations *fops);

这里,name 是要创建的文件的名称,mode 描述文件应具有的访问权限,parent 表示应保存文件的目录,数据将存储在生成的 inode 结构的 i_private 字段中,fops 是一组实现文件行为的文件操作。至少,应提供 read() 和/或 write() 操作;可以根据需要包含其他操作。同样,返回值将是指向创建文件的 dentry 指针,如果发生错误,则为 ERR_PTR(-ERROR),如果缺少 debugfs 支持,则为 ERR_PTR(-ENODEV)。

创建一个具有初始大小的文件,可以改用以下函数:

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);

file_size为初始文件大小,其他参数与函数debugfs_create_file相同。

在许多情况下,创建一组文件操作实际上并不是必要的;debugfs 代码为简单情况提供了许多辅助函数。可以使用以下任何一种方式创建包含单个整数值的文件:

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);

只要开发人员知道要导出的值的大小,这些函数就很有用。不过,有些类型在不同的架构上可能有不同的宽度,这会使情况变得有些复杂。有一些函数旨在帮助解决这种特殊情况:

void debugfs_create_size_t(const char *name, umode_t mode,
                           struct dentry *parent, size_t *value);

正如预期的那样,此函数将创建一个 debugfs 文件来表示 size_t 类型的变量。

类似地,对于十进制和十六进制的无符号长整型变量也有辅助函数:

struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
                                    struct dentry *parent,
                                    unsigned long *value);
void debugfs_create_xul(const char *name, umode_t mode,
                        struct dentry *parent, unsigned long *value);

可以将布尔值放置在 debugfs 中:

void debugfs_create_bool(const char *name, umode_t mode,
                         struct dentry *parent, bool *value);

读取结果文件将产生 Y(非零值)或 N,后跟换行符。如果写入,它将接受大写或小写值,或 1 或 0。任何其他输入将被忽略。

另外,可以使用以下命令将 atomic_t 值放置在 debugfs 中:

void debugfs_create_atomic_t(const char *name, umode_t mode,
                             struct dentry *parent, atomic_t *value)

读取此文件将获得 atomic_t 值,写入此文件将设置 atomic_t 值。

另一种选择是导出任意二进制数据块,具有以下结构和功能:

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);

读取此文件将返回 debugfs_blob_wrapper 结构指向的数据。一些驱动程序使用“blobs”作为返回几行(静态)格式化文本输出的简单方法。此函数可用于导出二进制信息,但主线中似乎没有任何代码可以这样做。请注意,使用创建的所有文件 debugfs_create_blob()都是只读的。

如果你想要转储一个寄存器块(在开发过程中这种情况经常发生,即使很少有这样的代码进入主线),debugfs 提供了两个功能:一个用于创建仅包含寄存器的文件,另一个用于在另一个顺序文件的中间插入一个寄存器块:

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);

“base” 参数可能是 0,但您可能希望使用 __stringify 构建 reg32 数组,并且许多寄存器名称(宏)实际上是寄存器块基数的字节偏移量。

如果你想要在 debugfs 中转储 u32 数组,你可以创建一个文件:

struct debugfs_u32_array {
    u32 *array;
    u32 n_elements;
};

void debugfs_create_u32_array(const char *name, umode_t mode,
                    struct dentry *parent,
                    struct debugfs_u32_array *array);

“array” 参数包装指向数组数据的指针及其元素数量。注意:一旦创建数组,其大小就无法更改。

有一个辅助函数可以创建与设备相关的 seq_file:

void debugfs_create_devm_seqfile(struct device *dev,
                             const char *name,
                             struct dentry *parent,
                             int (*read_fn)(struct seq_file *s,
                                     void *data));

“dev”参数是与该debugfs文件相关的设备,“read_fn”是一个函数指针,调用该函数来打印seq_file的内容。

还有一些其他面向目录的辅助函数:

struct dentry *debugfs_rename(struct dentry *old_dir,
                              struct dentry *old_dentry,
                              struct dentry *new_dir,
                              const char *new_name);

struct dentry *debugfs_create_symlink(const char *name,
                                      struct dentry *parent,
                                      const char *target);

调用debugfs_rename()将为现有的 debugfs 文件赋予新名称,可能位于不同的目录中。new_name 在调用之前不得存在;返回值是包含更新信息的 old_dentry。可以使用 创建符号链接debugfs_create_symlink()。

所有 debugfs 用户必须考虑一件重要的事情:debugfs 中创建的任何目录都不会自动清理。如果卸载模块时没有明确删除 debugfs 条目,结果将产生大量陈旧的指针,并且会产生无休止的反社会行为。因此,所有 debugfs 用户(至少是那些可以构建为模块的用户)必须准备好删除他们在那里创建的所有文件和目录。可以使用以下命令删除文件:

void debugfs_remove(struct dentry *dentry);

dentry 值可以是 NULL 或错误值,在这种情况下不会删除任何内容。

以前,debugfs 用户需要记住他们创建的每个 debugfs 文件的 dentry 指针,以便清理所有文件。不过,我们现在生活在更加文明的时代,debugfs 用户可以调用:

void debugfs_remove_recursive(struct dentry *dentry);

如果此函数传递了与顶级目录相对应的 dentry 的指针,则该目录下的整个层次结构将被删除。


http://www.kler.cn/a/456901.html

相关文章:

  • Unity 读Excel,读取xlsx文件解决方案
  • 【每日学点鸿蒙知识】ets匿名类、获取控件坐标、Web显示iframe标签、软键盘导致上移、改变Text的背景色
  • 【算法day27】动态规划:基础2
  • da白话讲深度学习-卷积网络
  • 24.12.30 SpringBoot
  • Fetch处理大模型流式数据请求与解析
  • Flutter 实现全局悬浮按钮学习
  • 微信小程序页面传参长度问题
  • Blender真实灰尘粒子动画资产预设 Dust Particles Pro V1.2
  • JVM常用参数
  • 《易经》在 Java 编程中的应用
  • Flutter 异步编程简述
  • 卷积神经网络(CNN)模型 CIFAR-10 数据集 例子
  • 学习,指针和FLASH
  • 02-18.python入门基础一基础算法
  • [江科大STM32] 第五集STM32工程模板——笔记
  • rk356x 下 qt 程序 hdmi不显示鼠标图标
  • 数值分析雨课堂章节测试
  • Java重要面试名词整理(十一):网络编程
  • 渗透测试常用术语总结
  • 深入了解JSON-LD:语义化网络数据的桥梁
  • v-if 和 v-show 的区别
  • anythingllm无法获取ollama模型
  • 在线学习平台-项目技术点-后台
  • 【计组】复习总结期末
  • 8.Java内置排序算法