Linux Debugfs文件系統(tǒng)介紹及使用author: jonathan
本文檔的CopyRight歸jonathan所有,可自由轉(zhuǎn)載,轉(zhuǎn)載時(shí)請(qǐng)保持文檔的完整性。 /*---------------------------------------------------------------------------------------------------------------------*/ 什么是不常見的文件系統(tǒng)?其實(shí)我也說不清,如ramfs->rootfs -> tmpfs ->initramfs->romfs->...等等,這些算不算呢?哎,算了,看到那里就算那里了。 1 Debugfs簡介 Debugfs文件系統(tǒng)目的是為開發(fā)人員提供更多內(nèi)核數(shù)據(jù),方便調(diào)試內(nèi)容. 我們知道/proc文件系統(tǒng)關(guān)注的是進(jìn)程信息,/sysfs關(guān)注是one-value-per-file策略集,而Debugfs文件系統(tǒng)沒有如此多限制,可是任何內(nèi)核要輸出的信息。 2 Debugfs使用 2.1 安裝文件系統(tǒng) Debugfs沒有物理設(shè)備,其掛載方式: mount -t debugfs none /sys/kernel/debug 2.2 編程使用 2.2.1 要使用Debugfs的模塊需要包含<linux/debugfs.h> 2.2.2 具體步驟 a 創(chuàng)建目錄。所有該模塊輸出的信息都在該目錄下面。 struct dentry *debugfs_create_dir(const char *name, struct dentry *parent); b 創(chuàng)建文件。在上面創(chuàng)建的目錄下面創(chuàng)建文件。 struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops); 通過fops操作文件的讀寫等請(qǐng)求,文件一般用來傳遞字符創(chuàng)等信息。 c 對(duì)于數(shù)字情況下,就沒有必須通過文件來傳遞信息了。Debugfs提供了針對(duì)數(shù)字的接口: struct dentry *debugfs_create_u8(const char *name, mode_t mode, struct dentry *parent, u8 *value); struct dentry *debugfs_create_u16(const char *name, mode_t mode, struct dentry *parent, u16 *value); struct dentry *debugfs_create_u32(const char *name, mode_t mode, struct dentry *parent, u32 *value); struct dentry *debugfs_create_u64(const char *name, mode_t mode, struct dentry *parent, u64 *value); struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value); struct dentry *debugfs_create_blob(const char *name, mode_t mode, struct dentry *parent, struct debugfs_blob_wrapper *blob); d 模塊卸載,需要主動(dòng)刪除目錄下的文件。 void debugfs_remove_recursive(struct dentry *dentry); 3 Debugfs內(nèi)核代碼分析 3.1 初始化和釋放資源 static int __init debugfs_init(void) { int retval; /* 創(chuàng)建kobject */ debug_kobj = kobject_create_and_add("debug", kernel_kobj); if (!debug_kobj) return -EINVAL; /* 注冊(cè)文件系統(tǒng) */ retval = register_filesystem(&debug_fs_type); if (retval) kobject_put(debug_kobj); else debugfs_registered = true; return retval; } static void __exit debugfs_exit(void) { debugfs_registered = false; simple_release_fs(&debugfs_mount, &debugfs_mount_count); unregister_filesystem(&debug_fs_type); kobject_put(debug_kobj); } 3.2 關(guān)鍵函數(shù) debugfs_create_file函數(shù)是關(guān)鍵函數(shù),其他接口基本都是該接口的wrapper。 3.2.1 變參數(shù)宏的定義 #define pr_debug(fmt, ...) do { \ dynamic_pr_debug(fmt, ##__VA_ARGS__); \ } while (0) dynamic_pr_debug 也是變參數(shù)的. 3.2.2 debugfs_create_file /* 掛載點(diǎn) */ static struct vfsmount *debugfs_mount; /* 引用計(jì)數(shù) */ static int debugfs_mount_count; static bool debugfs_registered; /* 多條目數(shù)據(jù)結(jié)構(gòu) */ struct debugfs_blob_wrapper { void *data; unsigned long size; }; static struct file_system_type debug_fs_type = { .owner = THIS_MODULE, .name = "debugfs", .get_sb = debug_get_sb, .kill_sb = kill_litter_super, }; struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent, void *data, const struct file_operations *fops) { struct dentry *dentry = NULL; int error; pr_debug("debugfs: creating file '%s'\n",name); /* 如果文件系統(tǒng)沒有掛載,首先掛載文件系統(tǒng);否則增加掛載點(diǎn)引用計(jì)數(shù) */ error = simple_pin_fs(&debug_fs_type, &debugfs_mount, &debugfs_mount_count); if (error) goto exit; /* 根據(jù)名稱創(chuàng)建文件或者目錄 */ error = debugfs_create_by_name(name, mode, parent, &dentry); if (error) { dentry = NULL; simple_release_fs(&debugfs_mount, &debugfs_mount_count); goto exit; } if (dentry->d_inode) { /* 給私有數(shù)據(jù)和文件操作接口 */ if (data) dentry->d_inode->i_private = data; if (fops) dentry->d_inode->i_fop = fops; } exit: return dentry; } int simple_pin_fs(struct file_system_type *type, struct vfsmount **mount, int *count) { struct vfsmount *mnt = NULL; spin_lock(&pin_fs_lock); /* 如果沒有掛載文件系統(tǒng),這里會(huì)自動(dòng)掛載文件系統(tǒng) */ if (unlikely(!*mount)) { spin_unlock(&pin_fs_lock); mnt = vfs_kern_mount(type, 0, type->name, NULL); if (IS_ERR(mnt)) return PTR_ERR(mnt); spin_lock(&pin_fs_lock); if (!*mount) *mount = mnt; } /* 增加掛載點(diǎn)引用計(jì)數(shù) */ mntget(*mount); ++*count; spin_unlock(&pin_fs_lock); mntput(mnt); return 0; } static int debugfs_create_by_name(const char *name, mode_t mode, struct dentry *parent, struct dentry **dentry) { int error = 0; /* If the parent is not specified, we create it in the root. * We need the root dentry to do this, which is in the super * block. A pointer to that is in the struct vfsmount that we * have around. */ /* 英文說和很明白了 */ if (!parent) { if (debugfs_mount && debugfs_mount->mnt_sb) { parent = debugfs_mount->mnt_sb->s_root; } } if (!parent) { pr_debug("debugfs: Ah! can not find a parent!\n"); return -EFAULT; } *dentry = NULL; mutex_lock(&parent->d_inode->i_mutex); /* namei.c中根據(jù)名稱查找目錄, 在以前的文件系統(tǒng)分析中有介紹,這里不再累贅. * 主要過程: 根據(jù)name,計(jì)算hash; 在name_hash_table查找dentry;如果沒有找到,則d_alloc;遍歷到結(jié)尾得到該文件的dentry */ *dentry = lookup_one_len(name, parent, strlen(name)); if (!IS_ERR(*dentry)) { /* 以下三函數(shù)首先對(duì)mode設(shè)置合時(shí)的模式,然后都最終調(diào)用debugfs_get_inode,建立dentry與inode的聯(lián)系*/ switch (mode & S_IFMT) { case S_IFDIR: error = debugfs_mkdir(parent->d_inode, *dentry, mode); break; case S_IFLNK: error = debugfs_link(parent->d_inode, *dentry, mode); break; default: error = debugfs_create(parent->d_inode, *dentry, mode); break; } dput(*dentry); } else error = PTR_ERR(*dentry); mutex_unlock(&parent->d_inode->i_mutex); return error; } /* 根據(jù)超級(jí)塊分配新的inode */ static struct inode *debugfs_get_inode(struct super_block *sb, int mode, dev_t dev) { struct inode *inode = new_inode(sb); if (inode) { inode->i_mode = mode; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); break; case S_IFREG: inode->i_fop = &debugfs_file_operations; break; case S_IFLNK: inode->i_op = &debugfs_link_operations; break; case S_IFDIR: inode->i_op = &simple_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 * (for "." entry) */ inc_nlink(inode); break; } } return inode; } const struct file_operations debugfs_file_operations = { .read = default_read_file, .write = default_write_file, .open = default_open, }; const struct file_operations simple_dir_operations = { .open = dcache_dir_open, .release = dcache_dir_close, .llseek = dcache_dir_lseek, .read = generic_read_dir, .readdir = dcache_readdir, .fsync = simple_sync_file, }; const struct inode_operations simple_dir_inode_operations = { .lookup = simple_lookup, }; 3.3 其他函數(shù) struct dentry *debugfs_create_dir(const char *name, struct dentry *parent) { return debugfs_create_file(name, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, parent, NULL, NULL); } struct dentry *debugfs_create_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value) { return debugfs_create_file(name, mode, parent, value, &fops_bool); } 由以上可以看出,其他的輸出信息都是debugfs_create_file的包裝,這里主要是debugfs_create_file函數(shù)最后一個(gè)參數(shù)struct file_operations不同而已。 這里以bool類型為例: static ssize_t read_file_bool(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { char buf[3]; /* 存儲(chǔ)內(nèi)部保存的數(shù)據(jù) */ u32 *val = file->private_data; if (*val) buf[0] = 'Y'; else buf[0] = 'N'; buf[1] = '\n'; buf[2] = 0x00; return simple_read_from_buffer(user_buf, count, ppos, buf, 2); } static ssize_t write_file_bool(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { char buf[32]; int buf_size; /* 存儲(chǔ)內(nèi)部保存的數(shù)據(jù) */ u32 *val = file->private_data; buf_size = min(count, (sizeof(buf)-1)); if (copy_from_user(buf, user_buf, buf_size)) return -EFAULT; switch (buf[0]) { case 'y': case 'Y': case '1': *val = 1; break; case 'n': case 'N': case '0': *val = 0; break; } return count; } static const struct file_operations fops_bool = { .read = read_file_bool, .write = write_file_bool, .open = default_open, |
|