核心子系統或裝置驅動可以直接編譯到核心,也可以編譯成模組,如果編譯到核心,可以使用前一節介紹的方法通過核心啟動參數來向它們傳遞參數,如果編譯成模組,則可以通過命令列在插入模組時傳遞參數,或者在運行時,通過sysfs來設定或讀模數塊資料。
Sysfs是一個基於記憶體的檔案系統,實際上它基於ramfs,sysfs提供了一種把核心資料結構、它們的屬性以及屬性與資料結構的聯絡開放給使用者態的方式,它與kobject子系統緊密地結合在一起,因此核心開發人員不需要直接使用它,而是核心的各個子系統使用它。使用者要想使用 sysfs 讀取和設定核心參數,僅需裝載 sysfs 就可以通過檔案操作應用來讀取和設定核心通過 sysfs 開放給使用者的各個參數:
# mkdir -p /sysfs
$ mount -t sysfs sysfs /sysfs
注意,不要把 sysfs 和 sysctl 混淆,sysctl 是核心的一些控制參數,其目的是方便使用者對核心的行為進行控制,而 sysfs 僅僅是把核心的 kobject 對象的層次關係與屬性開放給使用者查看,因此 sysfs 的絕大部分是唯讀,模組作為一個 kobject 也被出口到 sysfs,模組參數則是作為模組屬性出口的,核心實現者為模組的使用提供了更靈活的方式,允許使用者佈建模組參數在 sysfs 的可見度並允許使用者在編寫模組時設定這些參數在 sysfs 下的存取權限,然後使用者就可以通過sysfs 來查看和設定模組參數,從而使得使用者能在模組運行時控制模組行為。
對於模組而言,聲明為 static 的變數都可以通過命令列來設定,但要想在 sysfs下可見,必須通過宏 module_param 來顯式聲明,該宏有三個參數,第一個為參數名,即已經定義的變數名,第二個參數則為變數類型,可用的類型有 byte, short, ushort, int, uint, long, ulong, charp 和 bool 或 invbool,分別對應於 c 類型 char, short, unsigned short, int, unsigned int, long, unsigned long, char * 和 int,使用者也可以自訂類型 XXX(如果使用者自己定義了 param_get_XXX,param_set_XXX 和 param_check_XXX)。該宏的第三個參數用於指定存取權限,如果為 0,該參數將不出現在 sysfs 檔案系統中,允許的存取權限為 S_IRUSR, S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH 和 S_IWOTH 的組合,它們分別對應於使用者讀,使用者寫,使用者組讀,使用者組寫,其他使用者讀和其他使用者寫,因此用檔案的存取權限設定是一致的。
在原始碼中的核心模組 module-param-exam.c 是一個利用模組參數和sysfs來進行使用者態與核心態資料互動的例子。該模組有三個參數可以通過命令列設定,下面是作者系統上的運行結果樣本:
# insmod ./module-param-exam.ko my_invisible_int=10 my_visible_int=20 mystring="Hello,World"
my_invisible_int = 10
my_visible_int = 20
mystring = 'Hello,World'
# ls /sys/module/module_param_exam/parameters/
mystring my_visible_int
# cat /sys/module/module_param_exam/parameters/mystring
Hello,World
# cat /sys/module/module_param_exam/parameters/my_visible_int
20
# echo 2000 > /sys/module/module_param_exam/parameters/my_visible_int
# cat /sys/module/module_param_exam/parameters/my_visible_int
2000
# echo "abc" > /sys/module/module_param_exam/parameters/mystring
# cat /sys/module/module_param_exam/parameters/mystring
abc
# rmmod module_param_exam
my_invisible_int = 10
my_visible_int = 2000
mystring = 'abc'
以下為樣本源碼:
//filename: module-para-exam.c
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/stat.h>
static int my_invisible_int = 0;
static int my_visible_int = 0;
static char * mystring = "Hello, World";
module_param(my_invisible_int, int, 0);
MODULE_PARM_DESC(my_invisible_int, "An invisible int under sysfs");
module_param(my_visible_int, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(my_visible_int, "An visible int under sysfs");
module_param(mystring, charp, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
MODULE_PARM_DESC(mystring, "An visible string under sysfs");
static int __init exam_module_init(void)
{
printk("my_invisible_int = %d\n", my_invisible_int);
printk("my_visible_int = %d\n", my_visible_int);
printk("mystring = '%s'\n", mystring);
return 0;
}
static void __exit exam_module_exit(void)
{
printk("my_invisible_int = %d\n", my_invisible_int);
printk("my_visible_int = %d\n", my_visible_int);
printk("mystring = '%s'\n", mystring);
}
module_init(exam_module_init);
module_exit(exam_module_exit);
MODULE_AUTHOR("Yang Yi");
MODULE_DESCRIPTION("A module_param example module");
MODULE_LICENSE("GPL");