3.5. open 和 release

2018-02-24 15:49 更新

3.5.?open 和 release

到此我們已經(jīng)快速瀏覽了這些成員, 我們開始在真實(shí)的 scull 函數(shù)中使用它們.

3.5.1.?open 方法

open 方法提供給驅(qū)動(dòng)來做任何的初始化來準(zhǔn)備后續(xù)的操作. 在大部分驅(qū)動(dòng)中, open 應(yīng)當(dāng)進(jìn)行下面的工作:

  • 檢查設(shè)備特定的錯(cuò)誤(例如設(shè)備沒準(zhǔn)備好, 或者類似的硬件錯(cuò)誤

  • 如果它第一次打開, 初始化設(shè)備

  • 如果需要, 更新 f_op 指針.

  • 分配并填充要放進(jìn) filp->private_data 的任何數(shù)據(jù)結(jié)構(gòu)

但是, 事情的第一步常常是確定打開哪個(gè)設(shè)備. 記住 open 方法的原型是:


int (*open)(struct inode *inode, struct file *filp);

inode 參數(shù)有我們需要的信息,以它的 i_cdev 成員的形式, 里面包含我們之前建立的 cdev 結(jié)構(gòu). 唯一的問題是通常我們不想要 cdev 結(jié)構(gòu)本身, 我們需要的是包含 cdev 結(jié)構(gòu)的 scull_dev 結(jié)構(gòu). C 語言使程序員玩弄各種技巧來做這種轉(zhuǎn)換; 但是, 這種技巧編程是易出錯(cuò)的, 并且導(dǎo)致別人難于閱讀和理解代碼. 幸運(yùn)的是, 在這種情況下, 內(nèi)核 hacker 已經(jīng)為我們實(shí)現(xiàn)了這個(gè)技巧, 以 container_of 宏的形式, 在 <linux/kernel.h> 中定義:


container_of(pointer, container_type, container_field); 

這個(gè)宏使用一個(gè)指向 container_field 類型的成員的指針, 它在一個(gè) container_type 類型的結(jié)構(gòu)中, 并且返回一個(gè)指針指向包含結(jié)構(gòu). 在 scull_open, 這個(gè)宏用來找到適當(dāng)?shù)脑O(shè)備結(jié)構(gòu):


struct scull_dev *dev; /* device information */ 
dev = container_of(inode->i_cdev, struct scull_dev, cdev);
filp->private_data = dev; /* for other methods */

一旦它找到 scull_dev 結(jié)構(gòu), scull 在文件結(jié)構(gòu)的 private_data 成員中存儲(chǔ)一個(gè)它的指針, 為以后更易存取.

識(shí)別打開的設(shè)備的另外的方法是查看存儲(chǔ)在 inode 結(jié)構(gòu)的次編號(hào). 如果你使用 register_chrdev 注冊(cè)你的設(shè)備, 你必須使用這個(gè)技術(shù). 確認(rèn)使用 iminor 從 inode 結(jié)構(gòu)中獲取次編號(hào), 并且確定它對(duì)應(yīng)一個(gè)你的驅(qū)動(dòng)真正準(zhǔn)備好處理的設(shè)備.

scull_open 的代碼(稍微簡(jiǎn)化過)是:


int scull_open(struct inode *inode, struct file *filp)
{
        struct scull_dev *dev; /* device information */
        dev = container_of(inode->i_cdev, struct scull_dev, cdev);
        filp->private_data = dev; /* for other methods */

        /* now trim to 0 the length of the device if open was write-only */
        if ( (filp->f_flags & O_ACCMODE) == O_WRONLY)
        {
                scull_trim(dev); /* ignore errors */
        }
        return 0; /* success */
}

代碼看來相當(dāng)稀疏, 因?yàn)樵谡{(diào)用 open 時(shí)它沒有做任何特別的設(shè)備處理. 它不需要, 因?yàn)?scull 設(shè)備設(shè)計(jì)為全局的和永久的. 特別地, 沒有如"在第一次打開時(shí)初始化設(shè)備"等動(dòng)作, 因?yàn)槲覀儾粸?scull 保持打開計(jì)數(shù).

唯一在設(shè)備上的真實(shí)操作是當(dāng)設(shè)備為寫而打開時(shí)將它截取為長度為 0. 這樣做是因?yàn)? 在設(shè)計(jì)上, 用一個(gè)短的文件覆蓋一個(gè) scull 設(shè)備導(dǎo)致一個(gè)短的設(shè)備數(shù)據(jù)區(qū). 這類似于為寫而打開一個(gè)常規(guī)文件, 將其截短為 0. 如果設(shè)備為讀而打開, 這個(gè)操作什么都不做.

在我們查看其他 scull 特性的代碼時(shí)將看到一個(gè)真實(shí)的初始化如何起作用的.

3.5.2.?release 方法

release 方法的角色是 open 的反面. 有時(shí)你會(huì)發(fā)現(xiàn)方法的實(shí)現(xiàn)稱為 device_close, 而不是 device_release. 任一方式, 設(shè)備方法應(yīng)當(dāng)進(jìn)行下面的任務(wù):

  • 釋放 open 分配在 filp->private_data 中的任何東西

  • 在最后的 close 關(guān)閉設(shè)備

scull 的基本形式?jīng)]有硬件去關(guān)閉, 因此需要的代碼是最少的:[12]


int scull_release(struct inode *inode, struct file *filp)
{
 return 0;
}

你可能想知道當(dāng)一個(gè)設(shè)備文件關(guān)閉次數(shù)超過它被打開的次數(shù)會(huì)發(fā)生什么. 畢竟, dup 和 fork 系統(tǒng)調(diào)用不調(diào)用 open 來創(chuàng)建打開文件的拷貝; 每個(gè)拷貝接著在程序終止時(shí)被關(guān)閉. 例如, 大部分程序不打開它們的 stdin 文件(或設(shè)備), 但是它們都以關(guān)閉它結(jié)束. 當(dāng)一個(gè)打開的設(shè)備文件已經(jīng)真正被關(guān)閉時(shí)驅(qū)動(dòng)如何知道?

答案簡(jiǎn)單: 不是每個(gè) close 系統(tǒng)調(diào)用引起調(diào)用 release 方法. 只有真正釋放設(shè)備數(shù)據(jù)結(jié)構(gòu)的調(diào)用會(huì)調(diào)用這個(gè)方法 -- 因此得名. 內(nèi)核維持一個(gè)文件結(jié)構(gòu)被使用多少次的計(jì)數(shù). fork 和 dup 都不創(chuàng)建新文件(只有 open 這樣); 它們只遞增正存在的結(jié)構(gòu)中的計(jì)數(shù). close 系統(tǒng)調(diào)用僅在文件結(jié)構(gòu)計(jì)數(shù)掉到 0 時(shí)執(zhí)行 release 方法, 這在結(jié)構(gòu)被銷毀時(shí)發(fā)生. release 方法和 close 系統(tǒng)調(diào)用之間的這種關(guān)系保證了你的驅(qū)動(dòng)一次 open 只看到一次 release.

注意, flush 方法在每次應(yīng)用程序調(diào)用 close 時(shí)都被調(diào)用. 但是, 很少驅(qū)動(dòng)實(shí)現(xiàn) flush, 因?yàn)槌3T?close 時(shí)沒有什么要做, 除非調(diào)用 release.

如你會(huì)想到的, 前面的討論即便是應(yīng)用程序沒有明顯地關(guān)閉它打開的文件也適用: 內(nèi)核在進(jìn)程 exit 時(shí)自動(dòng)關(guān)閉了任何文件, 通過在內(nèi)部使用 close 系統(tǒng)調(diào)用.

[12] 其他風(fēng)味的設(shè)備由不同的函數(shù)關(guān)閉, 因?yàn)?scull_open 為每個(gè)設(shè)備替換了不同的 filp->f_op. 我們?cè)诮榻B每種風(fēng)味時(shí)再討論它們.

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)