close

原文網址 http://blog.xuite.net/tzeng015/twblog/113272242

 

在 Linux 下用戶空間與內核空間資料交換的九種方式,包括
http://svn.openfoundry.org/vwebsdk/Reference/switch.txt

 

在 Linux 下用戶空間與內核空間資料交換的九種方式,包括
1.	內核啟動參數 (__setup)
2.	模組參數與 sysfs (module_param)
3.	sysctl (register_sysctl_table)
4.	系統調用
5.	netlink     是一種雙向的資料交換方式,它使用起來非常簡單高效,特別是它的廣播特性在一些應用中非常方便。
6.	procfs      一般用于向用戶保留少量的數據訊息,或用戶透過它設置內核變量從而控制內核行為。
7.	seq_file    是單向的,即只能向內核傳遞,而不能從內核獲取,其餘的均可以進行雙向資料交換,即既可以從用戶應用傳遞給內核,有可以從內核傳遞給應用態應用。
                實際上倚賴于 procfs,因此為了使用 seq_file,必須使內核支持 procfs。
8.	debugfs     用于內核開發者調試使用,它比其他集中模式都方便,但是僅用于簡單類型的變量處理。
9.	relayfs     是一種非常複雜的數據交換模式,要想準確使用並不容易,但是如果使用得當,它遠比 procfs 和 seq_file 功能強大。

 

 

 

3. sysctl (register_sysctl_table)
sysctl 是一種用戶應用來設置和獲得運行時內核的配置參數的一種有效方式,
通過這種方式,用戶應用可以在內核運行的任何時刻來改變內核的配置參數,也可以在任何時候獲得內核的配置參數,
通常,內核的這些配置參數也出現在 proc 文件系統的 /proc/sys 目錄下,
用戶應用可以直接通過這個目錄下的文件來實現內核配置的讀寫操作,
例如,用戶可以通過
cat /proc/sys/net/ipv4/ip_forward
來得知內核IP層是否允許轉發IP包,用戶可以通過
echo 1 > /proc/sys/net/ipv4/ip_forward
把內核 IP 層設置為允許轉發 IP 包,即把該機器配置成一個路由器或閘道。
一般地,所有的 Linux 發佈也提供了一個系統工具 sysctl, 它可以設置和讀取內核的配置參數,
但是該工具依賴於 proc 文件系統,為了使用該工具,內核必須支援 proc 文件系統。
下面是使用 sysctl 工具來獲取和設置內核配置參數的例子:
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0
$ sysctl -w net.ipv4.ip_forward=1
net.ipv4.ip_forward = 1
$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 1
注意,參數 net.ipv4.ip_forward 實際被轉換到對應的 proc 文件 /proc/sys/net/ipv4/ip_forward
選項 -w 表示設置該內核配置參數,沒有選項表示讀內核配置參數,
用戶可以使用 sysctl -a 來讀取所有的內核配置參數,對應更多的 sysctl 工具的資訊,請參考手冊頁 sysctl(8)。

但是 proc 文件系統對 sysctl 不是必須的,在沒有 proc 文件系統的情況下,仍然可以,
這時需要使用內核提供的系統調用 sysctl 來實現對內核配置參數的設置和讀取。

例子
http://www-128.ibm.com/developerworks/cn/linux/l-kerns-usrs/program-examples.zip
在 program-examples 中給出了一個實際例副程式,它說明了如何在內核和用戶態使用 sysctl.

標頭檔 sysctl-exam.h 定義了 sysctl 列舉 ID,用戶態應用和內核模組需要這些 ID 來操作和註冊 sysctl 列舉。
內核模組在文件 sysctl-exam-kern.c 中實現,
在該內核模組中,每一個 sysctl 列舉對應一個 struct ctl_table (include/linux/sysctl.h) 結構,
struct ctl_table
{
int ctl_name; /* Binary ID */
const char *procname; /* Text ID for /proc/sys, or zero */
void *data;
int maxlen;
mode_t mode;
ctl_table *child;
ctl_table *parent; /* Automatically set */
proc_handler *proc_handler; /* Callback for text formatting */
ctl_handler *strategy; /* Callback function for all r/w */
void *extra1;
void *extra2;
};
ctl_name: 列舉的 ID
procname: 在 proc 下的名稱
data: 對應的內核變數, 注意該該欄位的賦值必須是指標
maxlen: 允許的最大長度, 它主要用於字串內核變數,以便在對該列舉設置時,對超過該最大長度的字串截掉後面超長的部分
mode: 在 proc 文件系統下的訪問許可權
proc_handler:在通過 proc 設置時的處理函數, 對於整型內核變數,應當設置為&proc_dointvec,而對於字串內核變數,則設置為 &proc_dostring
strategy: 字串處理策略, 一般這是為 &sysctl_string
Sysctl 列舉可以是目錄,此時 mode 欄位應當設置為 0555,
否則通過 sysctl 系統調用將無法訪問它下面的 sysctl 列舉,child 則指向該目錄列舉下面的所有列舉,
對於在同一目錄下的多個列舉,不必一一註冊,用戶可以把它們組織成一個 struct ctl_table 類型的陣列,然後一次註冊就可以,
但此時必須把陣列的最後一個結構設置為NULL,即
{
.ctl_name = 0
}

註冊 sysctl 列舉使用函數 register_sysctl_table(struct ctl_table *, int),
第一個參數為定義的 struct ctl_table 結構的 sysctl 列舉或列舉陣列指標,
第二個參數為插入到 sysctl 列舉表中的位置,如果插入到末尾,應當為0,如果插入到開頭,則為非0。
內核把所有的 sysctl 列舉都組織成 sysctl 表。

當模組卸載時,需要使用函數 unregister_sysctl_table(struct ctl_table_header *)
解註冊通過函數 register_sysctl_table 註冊的 sysctl 列舉,
函數 register_sysctl_table 在調用成功時返回結構 struct ctl_table_header,
它就是 sysctl 表的表頭,解註冊函數使用它來卸載相應的 sysctl 列舉。
用戶態應用 sysctl-exam-user.c 通過sysctl系統調用來查看和設置前面內核模組註冊的 sysctl 列舉
(當然如果用戶的系統內核已經支援 proc 文件系統,可以直接使用文件操作應用如 cat, echo 等直接查看和設置這些 sysctl 列舉)。
下面是作者運行該模組與應用的輸出結果示例:
$ insmod ./sysctl-exam-kern.ko
$ ./sysctl-user
mysysctl.myint = 0
mysysctl.mystring = ""
$ cat /proc/sys/mysysctl/myint
0
$ cat /proc/sys/mysysctl/mystring

$ ./sysctl-user 100 "Hello, World"
old value: mysysctl.myint = 0
new value: mysysctl.myint = 100
old vale: mysysctl.mystring = ""
new value: mysysctl.mystring = "Hello, World"
$ cat /proc/sys/mysysctl/myint
100
$ cat /proc/sys/mysysctl/mystring
Hello, World
$

arrow
arrow
    全站熱搜

    橘 發表在 痞客邦 留言(0) 人氣()