现在的位置: 首页 > 综合 > 正文

debugfs 分析

2013年09月02日 ⁄ 综合 ⁄ 共 5722字 ⁄ 字号 评论关闭

作者:杨红刚,兰州大学

邮箱:eagle.rtlinux@gmail.com / rtlinux@163.com

--------------------------------------------------------------------

------ 怎么使用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

抱歉!评论已关闭.