struct file, 定義於 <linux/fs.h>, 是設備驅動中第二個最重要的數據結構. 注意 file 與用戶空間程序的 FILE 指針沒有任何關系. 一個 FILE 定義在 C 庫中, 從不出現在內核 代碼中. 一個 struct file, 另一方面, 是一個內核結構, 從不出現在用戶程序中.
文件結構代表一個打開的文件. (它不特定給設備驅動; 系統中每個打開的文件有一個關聯 的 struct file 在內核空間). 它由內核在 open 時創建, 並傳遞給在文件上操作的任何 函數, 直到最后的關閉. 在文件的所有實例都關閉后, 內核釋放這個數據結構.
在內核源碼中, struct file 的指針常常稱為 file 或者 filp("file pointer"). 我們將 一直稱這個指針為 filp 以避免和結構自身混淆. 因此, file 指的是結構, 而 filp 是結 構指針.
注意, release 不是每次進程調用 close 時都被調用. 無論何時共享一個文件結構(例如, 在一個 fork 或 dup
之后), release 不會調用直到所有的拷貝都關閉了. 如果你需要在任一拷貝關閉時刷新掛着的數據, 你應當實現 flush 方法.
struct file 的最重要成員在這展示. 如同在前一節, 第一次閱讀可以跳過這個列表. 但 是, 在本章后面, 當我們面對一些真實 C 代碼時, 我們將更詳細討論這些成員.
mode_t f_mode;
文件模式確定文件是可讀的或者是可寫的(或者都是), 通過位 FMODE_READ 和 FMODE_WRITE. 你可能想在你的 open 或者 ioctl 函數中檢查這個成員的讀寫許可, 但是你不需要檢查讀寫許可, 因為內核在調用你的方法之前檢查. 當文件還沒有為 那種存取而打開時讀或寫的企圖被拒絕, 驅動甚至不知道這個情況.
loff_t f_pos;
當前讀寫位置. loff_t 在所有平台都是 64 位( 在 gcc 術語里是 long long ). 驅動可以讀這個值, 如果它需要知道文件中的當前位置, 但是正常地不應該改變它; 讀和寫應當使用它們作為最后參數而收到的指針來更新一個位置, 代替直接作用於 filp->f_pos. 這個規則的一個例外是在 llseek 方法中, 它的目的就是改變文件位 置.
unsigned int f_flags;
這些是文件標志, 例如 O_RDONLY, O_NONBLOCK, 和 O_SYNC. 驅動應當檢查 O_NONBLOCK 標志來看是否是請求非阻塞操作( 我們在第一章的"阻塞和非阻塞操作" 一節中討論非阻塞 I/O ); 其他標志很少使用. 特別地, 應當檢查讀/寫許可, 使用 f_mode 而不是 f_flags. 所有的標志在頭文件 <linux/fcntl.h> 中定義.
struct file_operations *f_op;
和文件關聯的操作. 內核安排指針作為它的 open 實現的一部分, 接着讀取它當它 需要分派任何的操作時. filp->f_op 中的值從不由內核保存為后面的引用; 這意味 着你可改變你的文件關聯的文件操作, 在你返回調用者之后新方法會起作用. 例如, 關聯到主編號 1 (/dev/null, /dev/zero, 等等)的 open 代碼根據打開的次編號來 替代 filp->f_op 中的操作. 這個做法允許實現幾種行為, 在同一個主編號下而不 必在每個系統調用中引入開銷. 替換文件操作的能力是面向對象編程的"方法重載" 的內核對等體.
void *private_data;
open 系統調用設置這個指針為 NULL, 在為驅動調用 open 方法之前. 你可自由使 用這個成員或者忽略它; 你可以使用這個成員來指向分配的數據, 但是接着你必須 記住在內核銷毀文件結構之前, 在 release 方法中釋放那個內存. private_data 是一個有用的資源, 在系統調用間保留狀態信息, 我們大部分例子模塊都使用它.
struct dentry *f_dentry;
關聯到文件的目錄入口( dentry )結構. 設備驅動編寫者正常地不需要關心 dentry 結構, 除了作為 filp->f_dentry->d_inode 存取 inode 結構.
真實結構有多幾個成員, 但是它們對設備驅動沒有用處. 我們可以安全地忽略這些成員, 因為驅動從不創建文件結構; 它們真實存取別處創建的結構.