重要的數(shù)據(jù)結(jié)構(gòu)-file_operations、file、inode
更多內(nèi)容請參考Linux設備驅(qū)動程序?qū)W習----目錄
重要的數(shù)據(jù)結(jié)構(gòu)
??上一節(jié)中設備編號的注冊僅僅是驅(qū)動程序代碼必須完成的許多工作中的第一件事。大部分基本大的驅(qū)動程序操作涉及到三個重要的內(nèi)核數(shù)據(jù)結(jié)構(gòu),分別是file_operations、file、inode。
文件操作file_operations結(jié)構(gòu)
??file_operations結(jié)構(gòu)用來將所有驅(qū)動程序操作連接到設備編號。該結(jié)構(gòu)定義在<linux/fs.h>中,其中包含了一組函數(shù)指針。每個打開的文件,和一組函數(shù)關(guān)聯(lián);文件在內(nèi)部由一個file結(jié)構(gòu)表示,函數(shù)組包含在指向一個file_operations結(jié)構(gòu)的fops字段。這些操作主要用來實現(xiàn)系統(tǒng)調(diào)用,如:read、write等。可以認為文件是一個“對象”,而操作它的函數(shù)是“方法”。
??file_operations結(jié)構(gòu)或者指向這類結(jié)構(gòu)的指針稱為fops,這個結(jié)構(gòu)中的每一個字段都必須指向驅(qū)動程序中實現(xiàn)特定操作的函數(shù),對于不支持的操作,對應的字段可置為NULL值。
??__user字符串,表明指針是一個用戶空間地址,因此不能被直接引用,對編譯來說,并沒有任何效果。
。。。。。
??scull設備驅(qū)動程序所實現(xiàn)的只是幾個重要的設備方法,如下初始化操作:
struct file_operations fops = {
.owner = THIS_MODULE,
.llseek = scull_llseek,
.read = scull_read,
.write = scull_write,
.ioctl = scull_ioctl,
.open = scull_open,
.release = scull_release,
};
??這個聲明操作采用了標準C的標記化結(jié)構(gòu)初始化語法。標記化的初始化方法允許對結(jié)構(gòu)成員進行重新排序。某些場合下,將頻繁被訪問的成員放在相同的硬件緩存行上,將大大提高性能。
file結(jié)構(gòu)
??file結(jié)構(gòu)代表一個打開的文件,它并不僅限定于設備驅(qū)動程序,系統(tǒng)中每個打開的文件在內(nèi)核空間都有一個對應的file結(jié)構(gòu)。file結(jié)構(gòu)由內(nèi)核在open時創(chuàng)建,并傳遞給在該文件上進行操作的所有函數(shù),直到最后的close函數(shù)。在文件的所有實例都被關(guān)閉之后,內(nèi)核會釋放這個file數(shù)據(jù)結(jié)構(gòu)。定義在頭文件<linux/fs.h>中,struct file是一個內(nèi)核結(jié)構(gòu),不會出現(xiàn)在用戶程序中。
??常用的結(jié)構(gòu)成員如下所示:
mode_t f_mode;
文件模式。通過FMODE_READ和FMODE_WRITE位來標識文件是否可讀或可寫或可讀寫。由于內(nèi)核在調(diào)用驅(qū)動程序的read和write前已經(jīng)檢查了訪問權(quán)限,所以驅(qū)動程序不必為這兩個方法檢查權(quán)限。
loff_t f_ops;
當前的讀/寫位置。loff_t是一個64位的數(shù)。用來修改文件位置。驅(qū)動程序可以讀取這個值來獲取文件中的當前位置。
unsigned int f_flags;
文件標志。如:O_RDONLY、O_NONBLOCK、O_SYNC。為了檢查用戶請求的是否是阻塞式操作。驅(qū)動程序需要檢查O_NONBLOCK標志。注意,檢查讀/寫權(quán)限應該查看f_mode而不是f_flags。標志定義在頭文件<linux/fcntl.h>中。
struct file_operations *f_op;
與文件相關(guān)的操作。內(nèi)核在執(zhí)行open操作時對這個指針賦值,以后需要處理這些操作時就讀取這個指針。
void *private_data;
open系統(tǒng)調(diào)用在調(diào)用驅(qū)動程序的open方法前將這個指針置為NULL。private_data是跨系統(tǒng)調(diào)用時保存狀態(tài)信息的非常有用的資源。
inode結(jié)構(gòu)
??內(nèi)核用inode結(jié)構(gòu)在內(nèi)部表示文件,和file結(jié)構(gòu)不同,file結(jié)構(gòu)表示打開的文件描述符。對單個文件,可能會由許多個表示打開的文件描述符的file結(jié)構(gòu),但它們都指向單個inode結(jié)構(gòu)。
??inode結(jié)構(gòu)中以下兩個字段對編寫驅(qū)動程序代碼比較重要:
dev_t i_rdev;
// 對表示設備文件的inode結(jié)構(gòu),該字段包含了真正的設備編號;
struct cdev \*i_cdev;
// struct cdev是表示字符設備的內(nèi)核的內(nèi)部結(jié)構(gòu)。當inode指向一個字符設備文件時,該字段包含了指向struct cdev結(jié)構(gòu)的指針;
??從一個inode中獲得主設備號和次設備號:
unsigned int imajor(struct inode *inode);
unsigned int iminor(struct inode *inode);
??為了防止因為內(nèi)核版本升級引起的不兼容問題,應該使用上面的兩個宏,而不是直接操作i_rdev。
更多內(nèi)容請參考Linux設備驅(qū)動程序?qū)W習----目錄