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 功能強大。


7. seq_file
一般地,內核透過在 procfs 文件系統下建立文件來向用戶空間提供輸出訊息,用戶空間可以透過任何文本閱讀應用查看該文件訊息,
但是 procfs 有一個缺陷,如果輸出內容大于1個內存頁,需要多次讀,因此處理起來很難,另外如果輸出太大,速度比較慢,
有時會出現一些意想不到的情況, Alexander Viro實現了一套新的功能,使得內核輸出大文件訊息更容易,
該功能出現下2.4.15(包括2.4.15)以後的所有2.4內核以及2.6內核中,尤其是在2.6內核中,已經大量地使用了該功能。

要想使用 seq_file 功能,開發者需要包含文件 linux/seq_file.h ,並定義與設置一個 seq_operations 結構(類似于 file_operations 結構):
struct seq_operations {
void * (*start) (struct seq_file *m, loff_t *pos);
void (*stop) (struct seq_file *m, void *v);
void * (*next) (struct seq_file *m, void *v, loff_t *pos);
int (*show) (struct seq_file *m, void *v);
};
start 函數用于指定seq_file文件的讀開始位置,返回實際讀開始位置,如果指定的位置超過文件末尾,應當返回NULL,
start 函數可以有一個特殊的返回SEQ_START_TOKEN,它用于讓 show 函數輸出文件頭,但這只能在 pos 為 0 時使用,
next 函數用于把 seq_file 文件的當前讀位置移動到下一個讀位置,返回實際的下一個讀位置,如果已經到達文件末尾,返回 NULL,
stop 函數用于在讀完 seq_file 文件后調用,它類似于文件操作 close,用于做一些必要的清理,如釋放內存等,
show 函數用于格式化輸出,如果成功返回0,否則返回出錯碼。

Seq_file 也定義了一些輔助函數用于格式化輸出:
int seq_putc(struct seq_file *m, char c);
函數 seq_putc 用于把一個字符輸出到seq_file文件。

int seq_puts(struct seq_file *m, const char *s);
函數 seq_puts 用于把一個字符串輸出到seq_file文件。

int seq_escape(struct seq_file *, const char *, const char *);
函數 seq_escape 類似于 seq_puts ,只是它將把第一個字元串參數中出現的包含在第二個字元串參數中的字符按照八進製形式輸出,也即對這些字符進行轉義處理。

int seq_printf(struct seq_file *, const char *, ...) __attribute__ ((format (printf,2,3)));
函數 seq_printf 是最常用的輸出函數,它用于把給定參數按照給定的格式輸出到seq_file文件。

int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
函數 seq_path 用于出文件名,字元串提供需要的文件名字符,它主要供文件系統使用。

在定義了架構 struct seq_operations 之后,用戶還需要把打開 seq_file 文件的 open 函數,以便該架構與對應于 seq_file 文件的 struct file 架構關聯起來,
例如,struct seq_operations定義為
struct seq_operations exam_seq_ops = {
.start = exam_seq_start,
.stop = exam_seq_stop,
.next = exam_seq_next,
.show = exam_seq_show
};

open 函數應該如下定義︰
static int exam_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &exam_seq_ops);
};

注意,函數 seq_open 是 seq_file 提供的函數,它用于把 struct seq_operations 架構 seq_file 文件關聯起來。
最後,用戶需要如下設置 struct file_operations 架構
struct file_operations exam_seq_file_ops = {
.owner = THIS_MODULE,
.open = exm_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release
};
注意,用戶需要建置 open 函數,其它的都是 seq_file 提供的函數。
然后,用戶創建一個 /proc 文件並把它的文件操作設置為 exam_seq_file_ops 即可︰

struct proc_dir_entry *entry;
entry = create_proc_entry("exam_seq_file", 0, NULL);
if (entry)
entry->proc_fops = &exam_seq_file_ops;

對于簡單的輸出, seq_file 用戶並不需要定義和設置這么多函數與架構,它僅需定義一個 show 函數,
然后使用 single_open 來定義 open 函數就可以,以下是使用這種簡單形式的一般步驟︰
1.定義一個show函數
int exam_show(struct seq_file *p, void *v)
{…}

2. 定義open函數
int exam_single_open(struct inode *inode, struct file *file)
{
return(single_open(file, exam_show, NULL));
}
注意要使用 single_open 而不是 seq_open。

3. 定義 struct file_operations 結構
struct file_operations exam_single_seq_file_operations = {
.open = exam_single_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};

注意,如果open函數使用了single_open,release 函數必須為 single_release,而不是 seq_release。
在 program-examples 中給出了一個使用 seq_file 的具體例子 seqfile_exam.c,
它使用 seq_file提供了一個查看當前系統營運的所有進程的 /proc界面,
在編譯並插入該模塊后,用戶透過命令"cat /proc/exam_esq_file"可以查看系統的所有進程。

arrow
arrow
    全站熱搜

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