1036168e3SChucheng Luo.. SPDX-License-Identifier: GPL-2.0 2036168e3SChucheng Luo 3036168e3SChucheng Luo.. include:: ../disclaimer-zh_CN.rst 4036168e3SChucheng Luo 5036168e3SChucheng Luo:Original: :ref:`Documentation/filesystems/debugfs.txt <debugfs_index>` 6036168e3SChucheng Luo 7036168e3SChucheng Luo======= 8036168e3SChucheng LuoDebugfs 9036168e3SChucheng Luo======= 10036168e3SChucheng Luo 11036168e3SChucheng Luo译者 12036168e3SChucheng Luo:: 13036168e3SChucheng Luo 14036168e3SChucheng Luo 中文版维护者: 罗楚成 Chucheng Luo <luochucheng@vivo.com> 15036168e3SChucheng Luo 中文版翻译者: 罗楚成 Chucheng Luo <luochucheng@vivo.com> 16036168e3SChucheng Luo 中文版校译者: 罗楚成 Chucheng Luo <luochucheng@vivo.com> 17036168e3SChucheng Luo 18036168e3SChucheng Luo 19036168e3SChucheng Luo 20036168e3SChucheng Luo版权所有2020 罗楚成 <luochucheng@vivo.com> 21036168e3SChucheng Luo 22036168e3SChucheng Luo 23036168e3SChucheng LuoDebugfs是内核开发人员在用户空间获取信息的简单方法。与/proc不同,proc只提供进程 24036168e3SChucheng Luo信息。也不像sysfs,具有严格的“每个文件一个值“的规则。debugfs根本没有规则,开发 25036168e3SChucheng Luo人员可以在这里放置他们想要的任何信息。debugfs文件系统也不能用作稳定的ABI接口。 26036168e3SChucheng Luo从理论上讲,debugfs导出文件的时候没有任何约束。但是[1]实际情况并不总是那么 27036168e3SChucheng Luo简单。即使是debugfs接口,也最好根据需要进行设计,并尽量保持接口不变。 28036168e3SChucheng Luo 29036168e3SChucheng Luo 30036168e3SChucheng LuoDebugfs通常使用以下命令安装:: 31036168e3SChucheng Luo 32036168e3SChucheng Luo mount -t debugfs none /sys/kernel/debug 33036168e3SChucheng Luo 34036168e3SChucheng Luo(或等效的/etc/fstab行)。 35036168e3SChucheng Luodebugfs根目录默认仅可由root用户访问。要更改对文件树的访问,请使用“ uid”,“ gid” 36036168e3SChucheng Luo和“ mode”挂载选项。请注意,debugfs API仅按照GPL协议导出到模块。 37036168e3SChucheng Luo 38036168e3SChucheng Luo使用debugfs的代码应包含<linux/debugfs.h>。然后,首先是创建至少一个目录来保存 39036168e3SChucheng Luo一组debugfs文件:: 40036168e3SChucheng Luo 41036168e3SChucheng Luo struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); 42036168e3SChucheng Luo 43036168e3SChucheng Luo如果成功,此调用将在指定的父目录下创建一个名为name的目录。如果parent参数为空, 44036168e3SChucheng Luo则会在debugfs根目录中创建。创建目录成功时,返回值是一个指向dentry结构体的指针。 45036168e3SChucheng Luo该dentry结构体的指针可用于在目录中创建文件(以及最后将其清理干净)。ERR_PTR 46036168e3SChucheng Luo(-ERROR)返回值表明出错。如果返回ERR_PTR(-ENODEV),则表明内核是在没有debugfs 47036168e3SChucheng Luo支持的情况下构建的,并且下述函数都不会起作用。 48036168e3SChucheng Luo 49036168e3SChucheng Luo在debugfs目录中创建文件的最通用方法是:: 50036168e3SChucheng Luo 51036168e3SChucheng Luo struct dentry *debugfs_create_file(const char *name, umode_t mode, 52036168e3SChucheng Luo struct dentry *parent, void *data, 53036168e3SChucheng Luo const struct file_operations *fops); 54036168e3SChucheng Luo 55036168e3SChucheng Luo在这里,name是要创建的文件的名称,mode描述了访问文件应具有的权限,parent指向 56036168e3SChucheng Luo应该保存文件的目录,data将存储在产生的inode结构体的i_private字段中,而fops是 57036168e3SChucheng Luo一组文件操作函数,这些函数中实现文件操作的具体行为。至少,read()和/或 58036168e3SChucheng Luowrite()操作应提供;其他可以根据需要包括在内。同样的,返回值将是指向创建文件 59036168e3SChucheng Luo的dentry指针,错误时返回ERR_PTR(-ERROR),系统不支持debugfs时返回值为ERR_PTR 60036168e3SChucheng Luo(-ENODEV)。创建一个初始大小的文件,可以使用以下函数代替:: 61036168e3SChucheng Luo 62036168e3SChucheng Luo struct dentry *debugfs_create_file_size(const char *name, umode_t mode, 63036168e3SChucheng Luo struct dentry *parent, void *data, 64036168e3SChucheng Luo const struct file_operations *fops, 65036168e3SChucheng Luo loff_t file_size); 66036168e3SChucheng Luo 67036168e3SChucheng Luofile_size是初始文件大小。其他参数跟函数debugfs_create_file的相同。 68036168e3SChucheng Luo 69036168e3SChucheng Luo在许多情况下,没必要自己去创建一组文件操作;对于一些简单的情况,debugfs代码提供 70036168e3SChucheng Luo了许多帮助函数。包含单个整数值的文件可以使用以下任何一项创建:: 71036168e3SChucheng Luo 72036168e3SChucheng Luo void debugfs_create_u8(const char *name, umode_t mode, 73036168e3SChucheng Luo struct dentry *parent, u8 *value); 74036168e3SChucheng Luo void debugfs_create_u16(const char *name, umode_t mode, 75036168e3SChucheng Luo struct dentry *parent, u16 *value); 76036168e3SChucheng Luo struct dentry *debugfs_create_u32(const char *name, umode_t mode, 77036168e3SChucheng Luo struct dentry *parent, u32 *value); 78036168e3SChucheng Luo void debugfs_create_u64(const char *name, umode_t mode, 79036168e3SChucheng Luo struct dentry *parent, u64 *value); 80036168e3SChucheng Luo 81036168e3SChucheng Luo这些文件支持读取和写入给定值。如果某个文件不支持写入,只需根据需要设置mode 82036168e3SChucheng Luo参数位。这些文件中的值以十进制表示;如果需要使用十六进制,可以使用以下函数 83036168e3SChucheng Luo替代:: 84036168e3SChucheng Luo 85036168e3SChucheng Luo void debugfs_create_x8(const char *name, umode_t mode, 86036168e3SChucheng Luo struct dentry *parent, u8 *value); 87036168e3SChucheng Luo void debugfs_create_x16(const char *name, umode_t mode, 88036168e3SChucheng Luo struct dentry *parent, u16 *value); 89036168e3SChucheng Luo void debugfs_create_x32(const char *name, umode_t mode, 90036168e3SChucheng Luo struct dentry *parent, u32 *value); 91036168e3SChucheng Luo void debugfs_create_x64(const char *name, umode_t mode, 92036168e3SChucheng Luo struct dentry *parent, u64 *value); 93036168e3SChucheng Luo 94036168e3SChucheng Luo这些功能只有在开发人员知道导出值的大小的时候才有用。某些数据类型在不同的架构上 95036168e3SChucheng Luo有不同的宽度,这样会使情况变得有些复杂。在这种特殊情况下可以使用以下函数:: 96036168e3SChucheng Luo 97036168e3SChucheng Luo void debugfs_create_size_t(const char *name, umode_t mode, 98036168e3SChucheng Luo struct dentry *parent, size_t *value); 99036168e3SChucheng Luo 100036168e3SChucheng Luo不出所料,此函数将创建一个debugfs文件来表示类型为size_t的变量。 101036168e3SChucheng Luo 102036168e3SChucheng Luo同样地,也有导出无符号长整型变量的函数,分别以十进制和十六进制表示如下:: 103036168e3SChucheng Luo 104036168e3SChucheng Luo struct dentry *debugfs_create_ulong(const char *name, umode_t mode, 105036168e3SChucheng Luo struct dentry *parent, 106036168e3SChucheng Luo unsigned long *value); 107036168e3SChucheng Luo void debugfs_create_xul(const char *name, umode_t mode, 108036168e3SChucheng Luo struct dentry *parent, unsigned long *value); 109036168e3SChucheng Luo 110036168e3SChucheng Luo布尔值可以通过以下方式放置在debugfs中:: 111036168e3SChucheng Luo 112036168e3SChucheng Luo struct dentry *debugfs_create_bool(const char *name, umode_t mode, 113036168e3SChucheng Luo struct dentry *parent, bool *value); 114036168e3SChucheng Luo 115036168e3SChucheng Luo 116036168e3SChucheng Luo读取结果文件将产生Y(对于非零值)或N,后跟换行符写入的时候,它只接受大写或小写 117036168e3SChucheng Luo值或1或0。任何其他输入将被忽略。 118036168e3SChucheng Luo 119036168e3SChucheng Luo同样,atomic_t类型的值也可以放置在debugfs中:: 120036168e3SChucheng Luo 121036168e3SChucheng Luo void debugfs_create_atomic_t(const char *name, umode_t mode, 122036168e3SChucheng Luo struct dentry *parent, atomic_t *value) 123036168e3SChucheng Luo 124036168e3SChucheng Luo读取此文件将获得atomic_t值,写入此文件将设置atomic_t值。 125036168e3SChucheng Luo 126036168e3SChucheng Luo另一个选择是通过以下结构体和函数导出一个任意二进制数据块:: 127036168e3SChucheng Luo 128036168e3SChucheng Luo struct debugfs_blob_wrapper { 129036168e3SChucheng Luo void *data; 130036168e3SChucheng Luo unsigned long size; 131036168e3SChucheng Luo }; 132036168e3SChucheng Luo 133036168e3SChucheng Luo struct dentry *debugfs_create_blob(const char *name, umode_t mode, 134036168e3SChucheng Luo struct dentry *parent, 135036168e3SChucheng Luo struct debugfs_blob_wrapper *blob); 136036168e3SChucheng Luo 137036168e3SChucheng Luo读取此文件将返回由指针指向debugfs_blob_wrapper结构体的数据。一些驱动使用“blobs” 138036168e3SChucheng Luo作为一种返回几行(静态)格式化文本的简单方法。这个函数可用于导出二进制信息,但 139036168e3SChucheng Luo似乎在主线中没有任何代码这样做。请注意,使用debugfs_create_blob()命令创建的 140036168e3SChucheng Luo所有文件是只读的。 141036168e3SChucheng Luo 142036168e3SChucheng Luo如果您要转储一个寄存器块(在开发过程中经常会这么做,但是这样的调试代码很少上传 143036168e3SChucheng Luo到主线中。Debugfs提供两个函数:一个用于创建仅寄存器文件,另一个把一个寄存器块 144036168e3SChucheng Luo插入一个顺序文件中:: 145036168e3SChucheng Luo 146036168e3SChucheng Luo struct debugfs_reg32 { 147036168e3SChucheng Luo char *name; 148036168e3SChucheng Luo unsigned long offset; 149036168e3SChucheng Luo }; 150036168e3SChucheng Luo 151036168e3SChucheng Luo struct debugfs_regset32 { 152036168e3SChucheng Luo struct debugfs_reg32 *regs; 153036168e3SChucheng Luo int nregs; 154036168e3SChucheng Luo void __iomem *base; 155036168e3SChucheng Luo }; 156036168e3SChucheng Luo 157036168e3SChucheng Luo struct dentry *debugfs_create_regset32(const char *name, umode_t mode, 158036168e3SChucheng Luo struct dentry *parent, 159036168e3SChucheng Luo struct debugfs_regset32 *regset); 160036168e3SChucheng Luo 161036168e3SChucheng Luo void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, 162036168e3SChucheng Luo int nregs, void __iomem *base, char *prefix); 163036168e3SChucheng Luo 164036168e3SChucheng Luo“base”参数可能为0,但您可能需要使用__stringify构建reg32数组,实际上有许多寄存器 165036168e3SChucheng Luo名称(宏)是寄存器块在基址上的字节偏移量。 166036168e3SChucheng Luo 167036168e3SChucheng Luo如果要在debugfs中转储u32数组,可以使用以下函数创建文件:: 168036168e3SChucheng Luo 169036168e3SChucheng Luo void debugfs_create_u32_array(const char *name, umode_t mode, 170036168e3SChucheng Luo struct dentry *parent, 171036168e3SChucheng Luo u32 *array, u32 elements); 172036168e3SChucheng Luo 173036168e3SChucheng Luo“array”参数提供数据,而“elements”参数为数组中元素的数量。注意:数组创建后,数组 174036168e3SChucheng Luo大小无法更改。 175036168e3SChucheng Luo 176036168e3SChucheng Luo有一个函数来创建与设备相关的seq_file:: 177036168e3SChucheng Luo 178036168e3SChucheng Luo struct dentry *debugfs_create_devm_seqfile(struct device *dev, 179036168e3SChucheng Luo const char *name, 180036168e3SChucheng Luo struct dentry *parent, 181036168e3SChucheng Luo int (*read_fn)(struct seq_file *s, 182036168e3SChucheng Luo void *data)); 183036168e3SChucheng Luo 184036168e3SChucheng Luo“dev”参数是与此debugfs文件相关的设备,并且“read_fn”是一个函数指针,这个函数在 185036168e3SChucheng Luo打印seq_file内容的时候被回调。 186036168e3SChucheng Luo 187036168e3SChucheng Luo还有一些其他的面向目录的函数:: 188036168e3SChucheng Luo 189036168e3SChucheng Luo struct dentry *debugfs_rename(struct dentry *old_dir, 190036168e3SChucheng Luo struct dentry *old_dentry, 191036168e3SChucheng Luo struct dentry *new_dir, 192036168e3SChucheng Luo const char *new_name); 193036168e3SChucheng Luo 194036168e3SChucheng Luo struct dentry *debugfs_create_symlink(const char *name, 195036168e3SChucheng Luo struct dentry *parent, 196036168e3SChucheng Luo const char *target); 197036168e3SChucheng Luo 198036168e3SChucheng Luo调用debugfs_rename()将为现有的debugfs文件重命名,可能同时切换目录。 new_name 199036168e3SChucheng Luo函数调用之前不能存在;返回值为old_dentry,其中包含更新的信息。可以使用 200036168e3SChucheng Luodebugfs_create_symlink()创建符号链接。 201036168e3SChucheng Luo 202036168e3SChucheng Luo所有debugfs用户必须考虑的一件事是: 203036168e3SChucheng Luo 204036168e3SChucheng Luodebugfs不会自动清除在其中创建的任何目录。如果一个模块在不显式删除debugfs目录的 205036168e3SChucheng Luo情况下卸载模块,结果将会遗留很多野指针,从而导致系统不稳定。因此,所有debugfs 206036168e3SChucheng Luo用户-至少是那些可以作为模块构建的用户-必须做模块卸载的时候准备删除在此创建的 207036168e3SChucheng Luo所有文件和目录。一份文件可以通过以下方式删除:: 208036168e3SChucheng Luo 209036168e3SChucheng Luo void debugfs_remove(struct dentry *dentry); 210036168e3SChucheng Luo 211036168e3SChucheng Luodentry值可以为NULL或错误值,在这种情况下,不会有任何文件被删除。 212036168e3SChucheng Luo 213036168e3SChucheng Luo很久以前,内核开发者使用debugfs时需要记录他们创建的每个dentry指针,以便最后所有 214036168e3SChucheng Luo文件都可以被清理掉。但是,现在debugfs用户能调用以下函数递归清除之前创建的文件:: 215036168e3SChucheng Luo 216036168e3SChucheng Luo void debugfs_remove_recursive(struct dentry *dentry); 217036168e3SChucheng Luo 218036168e3SChucheng Luo如果将对应顶层目录的dentry传递给以上函数,则该目录下的整个层次结构将会被删除。 219036168e3SChucheng Luo 220036168e3SChucheng Luo注释: 221036168e3SChucheng Luo[1] http://lwn.net/Articles/309298/ 222