xref: /OK3568_Linux_fs/kernel/Documentation/translations/zh_CN/filesystems/debugfs.rst (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun.. SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun
3*4882a593Smuzhiyun.. include:: ../disclaimer-zh_CN.rst
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun:Original: :doc:`../../../filesystems/debugfs`
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun=======
8*4882a593SmuzhiyunDebugfs
9*4882a593Smuzhiyun=======
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun译者
12*4882a593Smuzhiyun::
13*4882a593Smuzhiyun
14*4882a593Smuzhiyun	中文版维护者: 罗楚成 Chucheng Luo <luochucheng@vivo.com>
15*4882a593Smuzhiyun	中文版翻译者: 罗楚成 Chucheng Luo <luochucheng@vivo.com>
16*4882a593Smuzhiyun	中文版校译者:  罗楚成 Chucheng Luo <luochucheng@vivo.com>
17*4882a593Smuzhiyun
18*4882a593Smuzhiyun
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun版权所有2020 罗楚成 <luochucheng@vivo.com>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun
23*4882a593SmuzhiyunDebugfs是内核开发人员在用户空间获取信息的简单方法。与/proc不同,proc只提供进程
24*4882a593Smuzhiyun信息。也不像sysfs,具有严格的“每个文件一个值“的规则。debugfs根本没有规则,开发
25*4882a593Smuzhiyun人员可以在这里放置他们想要的任何信息。debugfs文件系统也不能用作稳定的ABI接口。
26*4882a593Smuzhiyun从理论上讲,debugfs导出文件的时候没有任何约束。但是[1]实际情况并不总是那么
27*4882a593Smuzhiyun简单。即使是debugfs接口,也最好根据需要进行设计,并尽量保持接口不变。
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun
30*4882a593SmuzhiyunDebugfs通常使用以下命令安装::
31*4882a593Smuzhiyun
32*4882a593Smuzhiyun    mount -t debugfs none /sys/kernel/debug
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun(或等效的/etc/fstab行)。
35*4882a593Smuzhiyundebugfs根目录默认仅可由root用户访问。要更改对文件树的访问,请使用“ uid”,“ gid”
36*4882a593Smuzhiyun和“ mode”挂载选项。请注意,debugfs API仅按照GPL协议导出到模块。
37*4882a593Smuzhiyun
38*4882a593Smuzhiyun使用debugfs的代码应包含<linux/debugfs.h>。然后,首先是创建至少一个目录来保存
39*4882a593Smuzhiyun一组debugfs文件::
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun    struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun如果成功,此调用将在指定的父目录下创建一个名为name的目录。如果parent参数为空,
44*4882a593Smuzhiyun则会在debugfs根目录中创建。创建目录成功时,返回值是一个指向dentry结构体的指针。
45*4882a593Smuzhiyun该dentry结构体的指针可用于在目录中创建文件(以及最后将其清理干净)。ERR_PTR
46*4882a593Smuzhiyun(-ERROR)返回值表明出错。如果返回ERR_PTR(-ENODEV),则表明内核是在没有debugfs
47*4882a593Smuzhiyun支持的情况下构建的,并且下述函数都不会起作用。
48*4882a593Smuzhiyun
49*4882a593Smuzhiyun在debugfs目录中创建文件的最通用方法是::
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun    struct dentry *debugfs_create_file(const char *name, umode_t mode,
52*4882a593Smuzhiyun				       struct dentry *parent, void *data,
53*4882a593Smuzhiyun				       const struct file_operations *fops);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun在这里,name是要创建的文件的名称,mode描述了访问文件应具有的权限,parent指向
56*4882a593Smuzhiyun应该保存文件的目录,data将存储在产生的inode结构体的i_private字段中,而fops是
57*4882a593Smuzhiyun一组文件操作函数,这些函数中实现文件操作的具体行为。至少,read()和/或
58*4882a593Smuzhiyunwrite()操作应提供;其他可以根据需要包括在内。同样的,返回值将是指向创建文件
59*4882a593Smuzhiyun的dentry指针,错误时返回ERR_PTR(-ERROR),系统不支持debugfs时返回值为ERR_PTR
60*4882a593Smuzhiyun(-ENODEV)。创建一个初始大小的文件,可以使用以下函数代替::
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun    struct dentry *debugfs_create_file_size(const char *name, umode_t mode,
63*4882a593Smuzhiyun				struct dentry *parent, void *data,
64*4882a593Smuzhiyun				const struct file_operations *fops,
65*4882a593Smuzhiyun				loff_t file_size);
66*4882a593Smuzhiyun
67*4882a593Smuzhiyunfile_size是初始文件大小。其他参数跟函数debugfs_create_file的相同。
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun在许多情况下,没必要自己去创建一组文件操作;对于一些简单的情况,debugfs代码提供
70*4882a593Smuzhiyun了许多帮助函数。包含单个整数值的文件可以使用以下任何一项创建::
71*4882a593Smuzhiyun
72*4882a593Smuzhiyun    void debugfs_create_u8(const char *name, umode_t mode,
73*4882a593Smuzhiyun			   struct dentry *parent, u8 *value);
74*4882a593Smuzhiyun    void debugfs_create_u16(const char *name, umode_t mode,
75*4882a593Smuzhiyun			    struct dentry *parent, u16 *value);
76*4882a593Smuzhiyun    struct dentry *debugfs_create_u32(const char *name, umode_t mode,
77*4882a593Smuzhiyun				      struct dentry *parent, u32 *value);
78*4882a593Smuzhiyun    void debugfs_create_u64(const char *name, umode_t mode,
79*4882a593Smuzhiyun			    struct dentry *parent, u64 *value);
80*4882a593Smuzhiyun
81*4882a593Smuzhiyun这些文件支持读取和写入给定值。如果某个文件不支持写入,只需根据需要设置mode
82*4882a593Smuzhiyun参数位。这些文件中的值以十进制表示;如果需要使用十六进制,可以使用以下函数
83*4882a593Smuzhiyun替代::
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun    void debugfs_create_x8(const char *name, umode_t mode,
86*4882a593Smuzhiyun			   struct dentry *parent, u8 *value);
87*4882a593Smuzhiyun    void debugfs_create_x16(const char *name, umode_t mode,
88*4882a593Smuzhiyun			    struct dentry *parent, u16 *value);
89*4882a593Smuzhiyun    void debugfs_create_x32(const char *name, umode_t mode,
90*4882a593Smuzhiyun			    struct dentry *parent, u32 *value);
91*4882a593Smuzhiyun    void debugfs_create_x64(const char *name, umode_t mode,
92*4882a593Smuzhiyun			    struct dentry *parent, u64 *value);
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun这些功能只有在开发人员知道导出值的大小的时候才有用。某些数据类型在不同的架构上
95*4882a593Smuzhiyun有不同的宽度,这样会使情况变得有些复杂。在这种特殊情况下可以使用以下函数::
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun    void debugfs_create_size_t(const char *name, umode_t mode,
98*4882a593Smuzhiyun			       struct dentry *parent, size_t *value);
99*4882a593Smuzhiyun
100*4882a593Smuzhiyun不出所料,此函数将创建一个debugfs文件来表示类型为size_t的变量。
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun同样地,也有导出无符号长整型变量的函数,分别以十进制和十六进制表示如下::
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun    struct dentry *debugfs_create_ulong(const char *name, umode_t mode,
105*4882a593Smuzhiyun					struct dentry *parent,
106*4882a593Smuzhiyun					unsigned long *value);
107*4882a593Smuzhiyun    void debugfs_create_xul(const char *name, umode_t mode,
108*4882a593Smuzhiyun			    struct dentry *parent, unsigned long *value);
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun布尔值可以通过以下方式放置在debugfs中::
111*4882a593Smuzhiyun
112*4882a593Smuzhiyun    struct dentry *debugfs_create_bool(const char *name, umode_t mode,
113*4882a593Smuzhiyun				       struct dentry *parent, bool *value);
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun读取结果文件将产生Y(对于非零值)或N,后跟换行符写入的时候,它只接受大写或小写
117*4882a593Smuzhiyun值或1或0。任何其他输入将被忽略。
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun同样,atomic_t类型的值也可以放置在debugfs中::
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun    void debugfs_create_atomic_t(const char *name, umode_t mode,
122*4882a593Smuzhiyun				 struct dentry *parent, atomic_t *value)
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun读取此文件将获得atomic_t值,写入此文件将设置atomic_t值。
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun另一个选择是通过以下结构体和函数导出一个任意二进制数据块::
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun    struct debugfs_blob_wrapper {
129*4882a593Smuzhiyun	void *data;
130*4882a593Smuzhiyun	unsigned long size;
131*4882a593Smuzhiyun    };
132*4882a593Smuzhiyun
133*4882a593Smuzhiyun    struct dentry *debugfs_create_blob(const char *name, umode_t mode,
134*4882a593Smuzhiyun				       struct dentry *parent,
135*4882a593Smuzhiyun				       struct debugfs_blob_wrapper *blob);
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun读取此文件将返回由指针指向debugfs_blob_wrapper结构体的数据。一些驱动使用“blobs”
138*4882a593Smuzhiyun作为一种返回几行(静态)格式化文本的简单方法。这个函数可用于导出二进制信息,但
139*4882a593Smuzhiyun似乎在主线中没有任何代码这样做。请注意,使用debugfs_create_blob()命令创建的
140*4882a593Smuzhiyun所有文件是只读的。
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun如果您要转储一个寄存器块(在开发过程中经常会这么做,但是这样的调试代码很少上传
143*4882a593Smuzhiyun到主线中。Debugfs提供两个函数:一个用于创建仅寄存器文件,另一个把一个寄存器块
144*4882a593Smuzhiyun插入一个顺序文件中::
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun    struct debugfs_reg32 {
147*4882a593Smuzhiyun	char *name;
148*4882a593Smuzhiyun	unsigned long offset;
149*4882a593Smuzhiyun    };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun    struct debugfs_regset32 {
152*4882a593Smuzhiyun	struct debugfs_reg32 *regs;
153*4882a593Smuzhiyun	int nregs;
154*4882a593Smuzhiyun	void __iomem *base;
155*4882a593Smuzhiyun    };
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun    struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
158*4882a593Smuzhiyun				     struct dentry *parent,
159*4882a593Smuzhiyun				     struct debugfs_regset32 *regset);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun    void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
162*4882a593Smuzhiyun			 int nregs, void __iomem *base, char *prefix);
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun“base”参数可能为0,但您可能需要使用__stringify构建reg32数组,实际上有许多寄存器
165*4882a593Smuzhiyun名称(宏)是寄存器块在基址上的字节偏移量。
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun如果要在debugfs中转储u32数组,可以使用以下函数创建文件::
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun     void debugfs_create_u32_array(const char *name, umode_t mode,
170*4882a593Smuzhiyun			struct dentry *parent,
171*4882a593Smuzhiyun			u32 *array, u32 elements);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun“array”参数提供数据,而“elements”参数为数组中元素的数量。注意:数组创建后,数组
174*4882a593Smuzhiyun大小无法更改。
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun有一个函数来创建与设备相关的seq_file::
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun   struct dentry *debugfs_create_devm_seqfile(struct device *dev,
179*4882a593Smuzhiyun				const char *name,
180*4882a593Smuzhiyun				struct dentry *parent,
181*4882a593Smuzhiyun				int (*read_fn)(struct seq_file *s,
182*4882a593Smuzhiyun					void *data));
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun“dev”参数是与此debugfs文件相关的设备,并且“read_fn”是一个函数指针,这个函数在
185*4882a593Smuzhiyun打印seq_file内容的时候被回调。
186*4882a593Smuzhiyun
187*4882a593Smuzhiyun还有一些其他的面向目录的函数::
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun    struct dentry *debugfs_rename(struct dentry *old_dir,
190*4882a593Smuzhiyun		                  struct dentry *old_dentry,
191*4882a593Smuzhiyun		                  struct dentry *new_dir,
192*4882a593Smuzhiyun				  const char *new_name);
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun    struct dentry *debugfs_create_symlink(const char *name,
195*4882a593Smuzhiyun                                          struct dentry *parent,
196*4882a593Smuzhiyun                                          const char *target);
197*4882a593Smuzhiyun
198*4882a593Smuzhiyun调用debugfs_rename()将为现有的debugfs文件重命名,可能同时切换目录。 new_name
199*4882a593Smuzhiyun函数调用之前不能存在;返回值为old_dentry,其中包含更新的信息。可以使用
200*4882a593Smuzhiyundebugfs_create_symlink()创建符号链接。
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun所有debugfs用户必须考虑的一件事是:
203*4882a593Smuzhiyun
204*4882a593Smuzhiyundebugfs不会自动清除在其中创建的任何目录。如果一个模块在不显式删除debugfs目录的
205*4882a593Smuzhiyun情况下卸载模块,结果将会遗留很多野指针,从而导致系统不稳定。因此,所有debugfs
206*4882a593Smuzhiyun用户-至少是那些可以作为模块构建的用户-必须做模块卸载的时候准备删除在此创建的
207*4882a593Smuzhiyun所有文件和目录。一份文件可以通过以下方式删除::
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun    void debugfs_remove(struct dentry *dentry);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyundentry值可以为NULL或错误值,在这种情况下,不会有任何文件被删除。
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun很久以前,内核开发者使用debugfs时需要记录他们创建的每个dentry指针,以便最后所有
214*4882a593Smuzhiyun文件都可以被清理掉。但是,现在debugfs用户能调用以下函数递归清除之前创建的文件::
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun    void debugfs_remove_recursive(struct dentry *dentry);
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun如果将对应顶层目录的dentry传递给以上函数,则该目录下的整个层次结构将会被删除。
219*4882a593Smuzhiyun
220*4882a593Smuzhiyun注释:
221*4882a593Smuzhiyun[1] http://lwn.net/Articles/309298/
222