作者:杨红刚,兰州大学
邮箱:[email protected] / [email protected]
--------------------------------------------------------------------
------ 怎么使用debugfs -------
在Documentation/filesystems/debugfs.txt中有详细的介绍。
具体例子参见另一篇博客:
使用debugfs导出调试信息--一个简单的例子
-------------------------------------------------
------------ debugfs 实现分析 -----------------------
1. debugfs的入口函数 // 没有卸载函数
debugfs_init()
- 在/sys/kernel/下创建一个debug目录,并返回一个和debug相关联的kobject对象的指针。
- 调用register_filesystem()注册debugfs。
- 前面的操作都正确时,debugfs_registered置为真,表示debugfs已经注册成功。
1'. debugfs_initialized() // EXPORT_SYMBOL
- 通过返回debugfs_registered告知调用者debugfs是否已经注册成功。
1.1 debugfs
static struct file_system_type debug_fs_type = {
.owner = THIS_MODULE,
.name = "debugfs",
.mount = debug_mount,
.kill_sb = kill_litter_super,
};
MODULE_ALIAS_FS("debugfs"); // fs-debugfs <-> debugfs
2. debug_mount()/ debug_fill_super() debugfs挂载 //模板
[1] 将文件系统的挂载参数保存到sb.s_options字段。该值用于super_operations.show_options()函数对文件系统
挂载参数的显示操作。
[2] 分配debugfs的私有数据结构debugfs_fs_info,并将其指针保存在超级块的s_fs_info中。
struct debugfs_mount_opts {
kuid_t uid;
kgid_t gid;
umode_t mode;
};
struct debugfs_fs_info {
struct debugfs_mount_opts mount_opts;
};
[3] 调用debugfs_parse_options()对debugfs的挂载参数进行解析。
解析挂载参数:uid=,gid=,mode=。
[4] 调用simple_fill_super(),初始化超级块的某些字段,创建和初始化根节点和根节点目录项。
[5] 将超级块操作函数集设置为debugfs_super_operations.
[6] 调用debugfs_apply_options()将挂载参数直保存在根节点的i_mode, i_uid, i_gid字段。
3. simple_fill_super(sb, DEBUGFS_MAGIC, debug_files) //模板
//这里忽略对debug_files的解释FIXME
[1] 设置超级块的s_blocksize,文件系统块的长度
s_blocksize_bits,文件系统块长度取以2底的对数
s_magic,文件系统的魔数
s_op,用于处理超级块的相关操作集合//此处设置为&simple_super_operations,之后还可以修改。
s_time_gran,文件系统支持的各种时间戳的最大可能的粒度,单位为ns
[2] 调用new_inode()创建一个新的inode,作为文件系统的根节点。
[3] 设置inode的i_ino,节点在VFS中的唯一的编号
i_mode, 模式S_IFDIR | 0755// 保存了访问权限(用户/组/其他)和文件类型(目录、设备文件等等)
i_atime,i_mtime,i_ctime,文件的修改时间,改变时间,创建时间
i_op,目录节点操作函数集为simple_dir_inode_operations
i_fop,目录节点的文件操作函数集为simple_dir_operations
__i_nlink,节点的链接计数值为2
[4] 调用d_make_root()为根节点创建并初始化一个目录项。
[5] 将根目录目录项保存在超级块的s_root字段。
4. debugfs_super_operations相关操作集
static const struct super_operations debugfs_super_operations = {
.statfs = simple_statfs,
.remount_fs = debugfs_remount,
.show_options = debugfs_show_options,
};
.statfs 给出文件系统的统计信息,例如使用和未使用的数据块的数目,或者文件名的最大长度。
.show_options / debugfs_show_options 显示文件系统的装载选项。
.remount_fs / debugfs_remount 重新解析文件系统的挂载选项(uid, gid, mode),并将其直保存在根节点的i_mode, i_uid, i_gid
字段。
----------------- 接口函数的实现 -------------------------
三个重要的变量:
static struct vfsmount *debugfs_mount; // 指向debugfs的挂载点描述信息结构
static int debugfs_mount_count; // debugfs的使用计数器,没创建一个debugfs文件都会将其值加一
static bool debugfs_registered; // true表示debugfs已经挂载,否则,没有挂载
1. static struct dentry *__create_file(const char *name, umode_t mode,
struct dentry *parent, void *data,
const struct file_operations *fops)
[1] 调用simple_pin_fs()对debugfs的使用计数值加一,并返回表示挂载点的vfmount指针
- 如果指向挂载点的指针mount为空,那么首先获取挂载点
- 调用vfs_kern_mount()
- 创建一个struct mount结构。
- 设置mount包含的vfsmount结构的mnt_flags为MNT_INTERNAL,表示"this is a kern_mount call"
- 调用mount_fs()执行debugfs的mount方法debug_mount(),得到其根目录项
- 设置vfsmout的mnt_root,当前debugfs的根目录的目录项
mnt_sb,debugfs的超级块
等等
- 调用mntget()对挂载点mount的mnt_count计数器加一
- 对count计数值增一
- 调用mntput()对挂载点mount的mnt_count计数值减一
- 将挂载点指针保存在*mount中。
[2] 调用lookup_one_len()从指定目录下寻找一个合适的目录项//如果没有指定就在debugfs的根目录下寻找
[3] 创建并返回文件的目录项的指针
根据要创建文件的类型:
S_IFDIR: debugfs_mkdir(),在@parent下创建文件夹@name
S_IFLNK: debugfs_link() 在@parent下创建链接文件@name
default: debugfs_create() 在@parent下创建普通文件@name
2. 作用:分配指定类型的inode并进行包括设置操作函数集在内的初始化操作。
static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev_t dev,
void *data, const struct file_operations *fops) // 模板
[1] 调用new_inode()创建一个inode结构,并初始化它的i_ino、i_mode、i_atime、i_mtime和i_ctime。
[2] 对于不同类型的文件设置不同的操作集:
S_IFREG: 对于普通文件,如果指定了文件操作函数集合,就使用fops设置对应的inode的文件操作集合i_fop
否则,使用默认的debugfs_file_operations。并将data保存到inode的私有字段i_private,便于操作。
S_IFLNK: 对于链接文件,设置inode节点操作函数集合debugfs_link_operations。并将data保存到inode的
私有字段i_private,方便操作。
S_IFDIR: 对于目录文件,设置inode节点操作函数集simple_dir_inode_operations,设置文件操作集合
simple_dir_operations。并将节点的i_nlink设置为2。
特殊节点:init_special_inode() ...
3. 作用:分配inode,初始化inode和相关的目录项dentry。
static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
umode_t mode, dev_t dev, void *data,
const struct file_operations *fops)
[1] 调用debugfs_get_inode()函数分配inode,并进行相应初始化。
[2] 调用d_instantiate()设置目录项dentry的inode相关的信息。
[3] 增加目录项dentry的引用直
4. 作用:在@dir下,创建文件夹。
static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
[1] 设置文件的权限标志和文件夹类型标志
[2] 调用debugfs_mknod()来分配inode,初始化inode和相关的目录项dentry
[3] 增加@dir的硬链接计数直。
[4] 文件夹创建成功
5. 作用:在@dir下,创建链接文件。
static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode,
void *data)
[1] 设置文件的权限标志和链接类型标志
[2] [2] 调用debugfs_mknod()来分配inode,初始化inode和相关的目录项dentr
6. 作用:在@dir下,创建普通文件。
static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
void *data, const struct file_operations *fops)
8. 导出的接口函数:
使用方法参见:Documentation/filesystems/debugfs.txt
debugfs_create_file - create a file in the debugfs filesystem
debugfs_create_dir - create a directory in the debugfs filesystem
debugfs_create_symlink- create a symbolic link in the debugfs filesystem
debugfs_remove - removes a file or directory from the debugfs filesystem
debugfs_remove_recursive - recursively removes a directory
debugfs_rename - rename a file/directory in the debugfs filesystem