3.5. open 和 release

2018-02-24 15:49 更新

3.5.?open 和 release

到此我們已經快速瀏覽了這些成員, 我們開始在真實的 scull 函數中使用它們.

3.5.1.?open 方法

open 方法提供給驅動來做任何的初始化來準備后續(xù)的操作. 在大部分驅動中, open 應當進行下面的工作:

  • 檢查設備特定的錯誤(例如設備沒準備好, 或者類似的硬件錯誤

  • 如果它第一次打開, 初始化設備

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

  • 分配并填充要放進 filp->private_data 的任何數據結構

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


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

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


container_of(pointer, container_type, container_field); 

這個宏使用一個指向 container_field 類型的成員的指針, 它在一個 container_type 類型的結構中, 并且返回一個指針指向包含結構. 在 scull_open, 這個宏用來找到適當的設備結構:


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 結構, scull 在文件結構的 private_data 成員中存儲一個它的指針, 為以后更易存取.

識別打開的設備的另外的方法是查看存儲在 inode 結構的次編號. 如果你使用 register_chrdev 注冊你的設備, 你必須使用這個技術. 確認使用 iminor 從 inode 結構中獲取次編號, 并且確定它對應一個你的驅動真正準備好處理的設備.

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


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 */
}

代碼看來相當稀疏, 因為在調用 open 時它沒有做任何特別的設備處理. 它不需要, 因為 scull 設備設計為全局的和永久的. 特別地, 沒有如"在第一次打開時初始化設備"等動作, 因為我們不為 scull 保持打開計數.

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

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

3.5.2.?release 方法

release 方法的角色是 open 的反面. 有時你會發(fā)現方法的實現稱為 device_close, 而不是 device_release. 任一方式, 設備方法應當進行下面的任務:

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

  • 在最后的 close 關閉設備

scull 的基本形式沒有硬件去關閉, 因此需要的代碼是最少的:[12]


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

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

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

注意, flush 方法在每次應用程序調用 close 時都被調用. 但是, 很少驅動實現 flush, 因為常常在 close 時沒有什么要做, 除非調用 release.

如你會想到的, 前面的討論即便是應用程序沒有明顯地關閉它打開的文件也適用: 內核在進程 exit 時自動關閉了任何文件, 通過在內部使用 close 系統(tǒng)調用.

[12] 其他風味的設備由不同的函數關閉, 因為 scull_open 為每個設備替換了不同的 filp->f_op. 我們在介紹每種風味時再討論它們.

以上內容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號