linux中設備節點是設備文件嗎?

linux驅動中,比如mknod建了設備節點demon,用open函數打來這個節點時返回一個fd,這個fd表示的是這個demon嗎?還有用open函數打開的時候會自動生成一個file結構體表示一個文件,這個文件表示的是這個demon嗎?


本回答響應 @唐浩然 的邀請,在他的回答上補充有疑問的地方。

首先,還是談談哲學:)。當我們討論程序概念的時候,我們盡量避免「XX是指XX」這樣的描述。弄佛的人特別喜歡用那個「指月亮」的例子來玩高深。這種小把戲在我們程序員看來不值一提,這個邏輯其實就是指針(索引),我們用手指指著月亮,手指是一個變數,月亮是另一個變數。我們盡量不說「手指是不是月亮?」這樣的話。

所以,文件永遠不是文件的名字,filp永遠不是設備,我們用索引關係,比如UML圖,來表述這裡的關係:

所以,用戶態通過mknod建立文件,VFS負責把它索引到對應的inode上,讓它和特定驅動關聯。用戶態調用open的時候,VFS再創建一個filep,並一起傳遞給那個驅動(register_chrdev的那個驅動),那個驅動本身有所有調用的回調,也可以給filp建立另一套回調,無所謂,之後其他調用就直接可以指向設備本身了。

這個應該回答原題的問題了。

然後回答動態模塊的問題:

內核的動態模塊原理和so的原理完全一樣,載入的時候同時展開代碼段和數據段,但實施上有所不同,so是lazy載入,沒有用到的時候不會真正載入到內存中,但內核是真正載入。

ko中的全局變數,和非ko的全局變數一樣,在模塊載入後就一直在系統中。

不存在「重要模塊」,模塊是否載入,都是init程序的配置引起的,如果init初始化樹中沒有載入動態模塊,就不會有任何動態模塊載入到系統中。

通常動態模塊不會「掃描」設備,動態模塊只會「驅動」設備。比如你有一個平台設備的ko,你載入進去了,init_module中註冊到platform_bus子系統中,platform_bus子系統會在註冊的時候用match函數給你match一次所有當初有人報過給它的所有device,如果device和你的註冊match,就會產生probe(),但你的驅動無權主動去掃描硬體的。反過來,如果是你的驅動先註冊,真正的設備後插入(比如USB key),這個事情會一樣發生。最終還是match,然後probe。

如果有其他疑問請繼續問吧。


我覺得還是要補充幾點:

inode 節點——&> 文件在內核態中的fs中的描述結構,和具體文件系統類型無關,不屬於哪一個進程,在內核的生命周期中一直存在於內存中,代表文件的實體。。。

file ——&> 文件在進程中的描述符,隨著進程死亡而被釋放。。

fd ——&> 為了封裝file的複雜性,提供給用戶在進程中索引file的一個索引號,fd只是打開的file的一個索引,進程真正操作的文件結構是file。。。。。

橋接模式——&> 也叫handle/body模式,Linux在file與inode直接模仿了橋接模式,只有open之後,file才與具體的inode橋接起來,互相通信,一旦close,或者進程死亡,file可以消失,inode卻隨內核繼續存在。通過橋接的隔離,file與inode可以分開進行各自的抽象和衍生,inode的組成元素有cdev, block_dev 等,因而向下可以管理操作各種字元設備,塊設備。。。

mknod——&>本質上是在/dev目錄下創建一個inode節點,/dev目錄一般有一個devtmpfs或者udevfs掛在在上面,也就是說mknod本質上就是創建/dev目錄下的inode節點,創建過程中,傳入的設備號,使得inode節點能在Linux內核中相關的註冊鏈表裡夠找到對應的cdev或者block_dev結構體橋接起來。。。

再回到橋接模式——&> file——&>inode ——&> cdev/block_device 中間可以看成兩個橋接,open使得file與inode橋接起來,mknod使得inode和cdev/block_device橋接起來,每個部分都可以獨自抽象衍生,和其它部分無關,只要調用的時候橋接起來就行。。。


mknod創建的文件是「設備文件」,區別與「普通文件」。

1: 設備驅動建立了這個設備node,這個Node 是設備文件,mknod時 程序使用設備的一個「介面」,通過此「介面」你可以訪問到它指向的具體設備。如果你沒有moknod ,在linux的「一切皆文件」的思想下,你怎麼才能訪問使用你的設備呢? 所以,「為設備建立一個文件吧」

2:當程序調用 open打開這 /dev/demon 的「文件時」, 此時的open僅僅是在VFS層面的open, VFS會在內存中創建一個 file_struct的結構,並返回一個fd, 其實fd 是和這個file_struct相關聯的:

比如在進程的files_struct結構中,有fd數組和fd_array數據,fd存放文件描述符,fd_array存放進程打開的 file_struct, 其中每個fd 指向fd_array中的一個元素。

3:fd_array中的存放的 是file_struct,每個file_struct結構中都 有一個類型為file_operations畢結構的指針f_op,f_op指向了一組 可以對文件進行的操作的函數(比如read)。當真正對文件進行操作時(比如read),f_op指向的操作函數(read)會調用 「針對該文件所屬的類型"的具體的真正的函數來執行操作。(比如:ext3_read() /MS_dos_read()).

所以對demon進行操作時,fd 和file_struct 最後還是 指向 了你所 創建的 demon代表的設備。

在一切皆文件的思路下,設備文件/dev/demon 可以理解為「你的設備在VSF中的一個符號鏈接(VFS的inode,設備文件沒有相應的磁碟inode(我在rhel6.5 x86_64:2.6.32-431環境下debugfs 看不到/dev下面文件的索引節點號),而普通的文件在磁碟是有inode的)」,當Open時,VSF為該inode(/dev/demon) 創建對應的 VSF的file_struct,以及fd。

fd和 file_struct 只是在你open設備時,在內存中創建, 可以把fd/file_struct 理解成 「你的設備在內存中的映射」。


推薦閱讀:

淺談Intel Core i5 8400 —— 一顆本不該如此低調的CPU
寫一個簡陋的程序,直接發布,是怎樣的體驗?
博弈論可以用於計算機的哪些領域?

TAG:軟體 | Linux | 計算機 | 嵌入式系統 | linux驅動 |