內核開發者經常需要向用戶空間應用輸出一些調試信息,在穩定的系統中可能根本不需要這些調試信息,但是在開發過程中,為了搞清楚內核的行為,調試信息非常必要,printk可能是用的最多的,但它并不是最好的,調試信息只是在開發中用于調試,而printk將一直輸出,因此開發完畢后需要清除不必要 的printk語句,另外如果開發者希望用戶空間應用能夠改變內核行為時,printk就無法實現。因此,需要一種新的機制,那只有在需要的時候使用,它在需要時通過在一個虛擬文件系統中創建一個或多個文件來向用戶空間應用提供調試信息。
有幾種方式可以實現上述要求:
(1)使用procfs,在/proc創建文件輸出調試信息,但是procfs對于大于一個內存頁(對于x86是4K)的輸出比較麻煩,而且速度慢,有時回出現一些意想不到的問題。
(2)使用sysfs(2.6內核引入的新的虛擬文件系統),在很多情況下,調試信息可以存放在那里,但是sysfs主要用于系統管理,它希望每一個文件對應內核的一個變量,如果使用它輸出復雜的數據結構或調試信息是非常困難的。
(3)使用libfs創建一個新的文件系統,該方法極其靈活,開發者可以為新文件系統設置一些規則,使用libfs使得創建新文件系統更加簡單,但是仍然超出了一個開發者的想象。
(4)為了使得開發者更加容易使用這樣的機制,Greg Kroah-Hartman開發了debugfs(在2.6.11中第一次引入),它是一個虛擬文件系統,專門用于輸出調試信息,該文件系統非常小,很容易使用,可以在配置內核時選擇是否構件到內核中,在不選擇它的情況下,使用它提供的API的內核部分不需要做任何改動。
使用debugfs的開發者首先需要在文件系統中創建一個目錄,下面函數用于在debugfs文件系統下創建一個目錄:
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent);
參數name是要創建的目錄名,參數parent指定創建目錄的父目錄的dentry,如果為NULL,目錄將創建在debugfs文件系統的根目錄下。如果返回為-ENODEV,表示內核沒有把debugfs編譯到其中,如果返回為NULL,表示其他類型的創建失敗,如果創建目錄成功,返回指向該 目錄對應的dentry條目的指針。
下面函數用于在debugfs文件系統中創建一個文件:
struct dentry *debugfs_create_file(const char *name, mode_t mode, struct dentry *parent,
void *data, struct file_operations *fops);
參數name指定要創建的文件名,參數mode指定該文件的訪問許可,參數parent指向該文件所在目錄,參數data為該文件特定的一些數據, 參數fops為實現在該文件上進行文件操作的fiel_operations結構指針,在很多情況下,由seq_file提供的文件操作實現就足夠了,因此使用debugfs很容易,當然,在一些情況下,開發者可能僅需要使用用戶應用可以控制的變量來調試,debugfs也提供了4個這樣的API方便開發者使用:
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_bool(const char *name, mode_t mode, struct dentry *parent, u32 *value);
參數name和mode指定文件名和訪問許可,參數value為需要讓用戶應用控制的內核變量指針。
當內核模塊卸載時,Debugfs并不會自動清除該模塊創建的目錄或文件,因此對于創建的每一個文件或目錄,開發者必須調用下面函數清除:
void debugfs_remove(struct dentry *dentry);
參數dentry為上面創建文件和目錄的函數返回的dentry指針。
在下面給出了一個使用debufs的示例模塊debugfs_exam.c,為了保證該模塊正確運行,必須讓內核支持debugfs, debugfs是一個調試功能,因此它位于主菜單Kernel hacking,并且必須選擇Kernel debugging選項才能選擇,它的選項名稱為Debug Filesystem。為了在用戶態使用debugfs,用戶必須mount它,下面是在作者系統上的使用輸出:
$ mkdir -p /debugfs
$ mount -t debugfs debugfs /debugfs
$ insmod 。/debugfs_exam.ko
$ ls /debugfs
debugfs-exam
$ ls /debugfs/debugfs-exam
u8_var u16_var u32_var bool_var
$ cd /debugfs/debugfs-exam
$ cat u8_var
0
$ echo 200 》 u8_var
$ cat u8_var
200
$ cat bool_var
N
$ echo 1 》 bool_var
$ cat bool_var
Y
//kernel module: debugfs_exam.c
#include 《linux/config.h》
#include 《linux/module.h》
#include 《linux/debugfs.h》
#include 《linux/types.h》
/*dentry:目錄項,是Linux文件系統中某個索引節點(inode)的鏈接。這個索引節點可以是文件,也可以是目錄。
Linux用數據結構dentry來描述fs中和某個文件索引節點相鏈接的一個目錄項(能是文件,也能是目錄)。
(1)未使用(unused)狀態:該dentry對象的引用計數d_count的值為0,但其d_inode指針仍然指向相關
的的索引節點。該目錄項仍然包含有效的信息,只是當前沒有人引用他。這種dentry對象在回收內存時可能會被釋放。
(2)正在使用(inuse)狀態:處于該狀態下的dentry對象的引用計數d_count大于0,且其d_inode指向相關
的inode對象。這種dentry對象不能被釋放。
(3)負(negative)狀態:和目錄項相關的inode對象不復存在(相應的磁盤索引節點可能已被刪除),dentry
對象的d_inode指針為NULL。但這種dentry對象仍然保存在dcache中,以便后續對同一文件名的查找能夠快速完成。
這種dentry對象在回收內存時將首先被釋放。
*/
static struct dentry *root_entry, *u8_entry, *u16_entry, *u32_entry, *bool_entry;
static u8 var8;
static u16 var16;
static u32 var32;
static u32 varbool;
static int __init exam_debugfs_init(void)
{
root_entry = debugfs_create_dir(“debugfs-exam”, NULL);
if (!root_entry) {
printk(“Fail to create proc dir: debugfs-exam\n”);
return 1;
}
u8_entry = debugfs_create_u8(“u8-var”, 0644, root_entry, &var8);
u16_entry = debugfs_create_u16(“u16-var”, 0644, root_entry, &var16);
u32_entry = debugfs_create_u32(“u32-var”, 0644, root_entry, &var32);
bool_entry = debugfs_create_bool(“bool-var”, 0644, root_entry, &varbool);
return 0;
}
static void __exit exam_debugfs_exit(void)
{
debugfs_remove(u8_entry);
debugfs_remove(u16_entry);
debugfs_remove(u32_entry);
debugfs_remove(bool_entry);
debugfs_remove(root_entry);
}
module_init(exam_debugfs_init);
module_exit(exam_debugfs_exit);
MODULE_LICENSE(“GPL”);
評論
查看更多