Linux設備驅(qū)動程序?qū)W習----10.重要的數(shù)據(jù)結(jié)構(gòu)

重要的數(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習----目錄

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容