第18章塊設(shè)備驅(qū)動程序_第1頁
第18章塊設(shè)備驅(qū)動程序_第2頁
第18章塊設(shè)備驅(qū)動程序_第3頁
第18章塊設(shè)備驅(qū)動程序_第4頁
第18章塊設(shè)備驅(qū)動程序_第5頁
已閱讀5頁,還剩40頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、第第1818章章 塊設(shè)備驅(qū)動程序塊設(shè)備驅(qū)動程序除了字符設(shè)備、網(wǎng)絡(luò)設(shè)備外,除了字符設(shè)備、網(wǎng)絡(luò)設(shè)備外,Linux系統(tǒng)中還有塊設(shè)備。字符系統(tǒng)中還有塊設(shè)備。字符設(shè)備和塊設(shè)備在內(nèi)核中的結(jié)構(gòu)有很大的不同,總體來說,塊設(shè)備要設(shè)備和塊設(shè)備在內(nèi)核中的結(jié)構(gòu)有很大的不同,總體來說,塊設(shè)備要比字符設(shè)備復(fù)雜很多。塊設(shè)備主要包含磁盤設(shè)備、比字符設(shè)備復(fù)雜很多。塊設(shè)備主要包含磁盤設(shè)備、SD卡等,這些設(shè)卡等,這些設(shè)備是備是Linux系統(tǒng)中不可缺少的存儲設(shè)備。計算機(jī)中都需要這樣的設(shè)系統(tǒng)中不可缺少的存儲設(shè)備。計算機(jī)中都需要這樣的設(shè)備來存儲數(shù)據(jù),所以學(xué)會塊設(shè)備驅(qū)動程序的寫法是非常重要的。備來存儲數(shù)據(jù),所以學(xué)會塊設(shè)備驅(qū)動程序的寫法是非

2、常重要的。18.1 18.1 塊設(shè)備簡介塊設(shè)備簡介本節(jié)對塊設(shè)備的相關(guān)概念進(jìn)行了簡要的分析。理解這本節(jié)對塊設(shè)備的相關(guān)概念進(jìn)行了簡要的分析。理解這些概念對寫塊設(shè)備驅(qū)動程序具有十分重要的意義。些概念對寫塊設(shè)備驅(qū)動程序具有十分重要的意義。18.1.1 18.1.1 塊設(shè)備總體概述塊設(shè)備總體概述Linux內(nèi)核中,內(nèi)核中,I/O設(shè)備大致分為兩類:塊設(shè)備和字符設(shè)備。塊設(shè)備大致分為兩類:塊設(shè)備和字符設(shè)備。塊設(shè)備將信息存儲在固定大小的塊中,每個塊都有自己的地址。數(shù)據(jù)設(shè)備將信息存儲在固定大小的塊中,每個塊都有自己的地址。數(shù)據(jù)塊的大小通常在塊的大小通常在512字節(jié)到字節(jié)到4K字節(jié)之間。塊設(shè)備的基本特征是每個塊字節(jié)之

3、間。塊設(shè)備的基本特征是每個塊都能獨(dú)立于其它塊而讀寫。磁盤就是最常見的塊設(shè)備。在都能獨(dú)立于其它塊而讀寫。磁盤就是最常見的塊設(shè)備。在Linux內(nèi)核內(nèi)核中,塊設(shè)備與內(nèi)核其他模塊的關(guān)系如圖所示:中,塊設(shè)備與內(nèi)核其他模塊的關(guān)系如圖所示:18.1.2 18.1.2 塊設(shè)備的結(jié)構(gòu)塊設(shè)備的結(jié)構(gòu)在寫塊設(shè)備驅(qū)動程序之前,了解典型塊設(shè)備的結(jié)構(gòu)是在寫塊設(shè)備驅(qū)動程序之前,了解典型塊設(shè)備的結(jié)構(gòu)是非常重要的。圖顯示的是磁盤的一個盤面,一些重要的概念非常重要的。圖顯示的是磁盤的一個盤面,一些重要的概念將在下面講述。將在下面講述。18.2 18.2 塊設(shè)備驅(qū)動程序的架構(gòu)塊設(shè)備驅(qū)動程序的架構(gòu)相對于字符設(shè)備來說,塊設(shè)備的驅(qū)動程序架

4、構(gòu)要稍微相對于字符設(shè)備來說,塊設(shè)備的驅(qū)動程序架構(gòu)要稍微復(fù)雜一些,其中涉及到很多重要的概念。對這些概念的理解復(fù)雜一些,其中涉及到很多重要的概念。對這些概念的理解是編寫驅(qū)動程序的前提,本節(jié)將對塊設(shè)備的整體架構(gòu)進(jìn)行詳是編寫驅(qū)動程序的前提,本節(jié)將對塊設(shè)備的整體架構(gòu)進(jìn)行詳細(xì)講解。細(xì)講解。18.2.1 18.2.1 塊設(shè)備加載過程塊設(shè)備加載過程在塊設(shè)備的模塊加載函數(shù)中,需要完成的一些重要工作,在塊設(shè)備的模塊加載函數(shù)中,需要完成的一些重要工作,這些工作涉及到的一些重要概念,將在后面的小節(jié)中進(jìn)行講解,這些工作涉及到的一些重要概念,將在后面的小節(jié)中進(jìn)行講解,本節(jié)的目的是為了給出一個整體的概念。塊設(shè)備驅(qū)動加載模塊

5、中本節(jié)的目的是為了給出一個整體的概念。塊設(shè)備驅(qū)動加載模塊中需要完成的工作如下圖所示:需要完成的工作如下圖所示:18.2.2 18.2.2 塊設(shè)備卸載過程塊設(shè)備卸載過程在塊設(shè)備驅(qū)動的卸載模塊中完成與模塊加載函數(shù)相反的工在塊設(shè)備驅(qū)動的卸載模塊中完成與模塊加載函數(shù)相反的工作。作。(1)使用)使用del_gendisk()函數(shù)刪除函數(shù)刪除gendisk設(shè)備,并使用設(shè)備,并使用put_disk()函數(shù)刪除對函數(shù)刪除對gendisk設(shè)備的引用。設(shè)備的引用。(2)使用)使用blk_cleanup_queue()函數(shù)清除請求隊(duì)列,并釋放函數(shù)清除請求隊(duì)列,并釋放請求隊(duì)列所占用的資源。請求隊(duì)列所占用的資源。(3)

6、如果在模塊加載函數(shù)中使用了)如果在模塊加載函數(shù)中使用了register_blkdev()注冊設(shè)注冊設(shè)備,那么需要在模塊卸載函數(shù)中使用備,那么需要在模塊卸載函數(shù)中使用unregister_blkdev()函數(shù)注函數(shù)注銷塊設(shè)備,并釋放對塊設(shè)備的引用。銷塊設(shè)備,并釋放對塊設(shè)備的引用。18.3 18.3 通用塊層通用塊層通用塊層是塊設(shè)備驅(qū)動的核心部分,這部分主要包含通用塊層是塊設(shè)備驅(qū)動的核心部分,這部分主要包含塊設(shè)備驅(qū)動程序的通用代碼部分。本節(jié)將介紹通用塊層的主塊設(shè)備驅(qū)動程序的通用代碼部分。本節(jié)將介紹通用塊層的主要函數(shù)和數(shù)據(jù)結(jié)構(gòu)。要函數(shù)和數(shù)據(jù)結(jié)構(gòu)。18.3.1 18.3.1 通用塊層通用塊層通用塊層是

7、一個內(nèi)核組件,它處理來自系統(tǒng)其他組件發(fā)出的塊設(shè)通用塊層是一個內(nèi)核組件,它處理來自系統(tǒng)其他組件發(fā)出的塊設(shè)備請求。換句話說,通用塊層包含了塊設(shè)備操作的一些通用函數(shù)和數(shù)備請求。換句話說,通用塊層包含了塊設(shè)備操作的一些通用函數(shù)和數(shù)據(jù)結(jié)構(gòu)。圖是塊設(shè)備加載函數(shù)中用到的一些重要數(shù)據(jù)結(jié)構(gòu),如通用磁據(jù)結(jié)構(gòu)。圖是塊設(shè)備加載函數(shù)中用到的一些重要數(shù)據(jù)結(jié)構(gòu),如通用磁盤結(jié)構(gòu)盤結(jié)構(gòu)gendisk k、請求隊(duì)列結(jié)構(gòu)請求隊(duì)列結(jié)構(gòu)request_queue、請求結(jié)構(gòu)、請求結(jié)構(gòu)requestrequest、塊、塊設(shè)備設(shè)備I/OI/O操作結(jié)構(gòu)操作結(jié)構(gòu)biobio、塊設(shè)備操作結(jié)構(gòu)塊設(shè)備操作結(jié)構(gòu)block_device_operatio

8、ns等。這等。這些結(jié)構(gòu)將在下面的幾小節(jié)詳細(xì)簡述。些結(jié)構(gòu)將在下面的幾小節(jié)詳細(xì)簡述。18.3.2 alloc_disk()18.3.2 alloc_disk()函數(shù)對應(yīng)的函數(shù)對應(yīng)的gendiskgendisk結(jié)構(gòu)體結(jié)構(gòu)體現(xiàn)實(shí)生活中有許多具體的物理塊設(shè)備,例如磁盤、光現(xiàn)實(shí)生活中有許多具體的物理塊設(shè)備,例如磁盤、光盤等。不同的物理塊設(shè)備其結(jié)構(gòu)是不一樣的,為了將這些塊盤等。不同的物理塊設(shè)備其結(jié)構(gòu)是不一樣的,為了將這些塊設(shè)備公用屬性在內(nèi)核中統(tǒng)一,內(nèi)核開發(fā)者定義了一個設(shè)備公用屬性在內(nèi)核中統(tǒng)一,內(nèi)核開發(fā)者定義了一個gendisk結(jié)構(gòu)體來描述磁盤。結(jié)構(gòu)體來描述磁盤。gendisk是是general disk的簡

9、稱,的簡稱,一般稱為通用磁盤。一般稱為通用磁盤。18.3.3 18.3.3 塊設(shè)備的注冊和注銷塊設(shè)備的注冊和注銷為了使內(nèi)核知道塊設(shè)備的存在,需要使用塊設(shè)備注冊為了使內(nèi)核知道塊設(shè)備的存在,需要使用塊設(shè)備注冊函數(shù)。在不使用塊設(shè)備時,也需要注銷塊設(shè)備。塊設(shè)備的注函數(shù)。在不使用塊設(shè)備時,也需要注銷塊設(shè)備。塊設(shè)備的注冊和注銷如下所述:冊和注銷如下所述:1注冊塊設(shè)備函數(shù)注冊塊設(shè)備函數(shù)register_blkdev()2注銷塊設(shè)備函數(shù)注銷塊設(shè)備函數(shù)unregister_blkdev()18.3.4 18.3.4 請求隊(duì)列請求隊(duì)列簡單的講,一個塊設(shè)備的請求隊(duì)列就是包含塊設(shè)備簡單的講,一個塊設(shè)備的請求隊(duì)列就是包

10、含塊設(shè)備I/O請求的一請求的一個隊(duì)列。這個隊(duì)列使用鏈表線性的排列。請求隊(duì)列中存儲未完成的個隊(duì)列。這個隊(duì)列使用鏈表線性的排列。請求隊(duì)列中存儲未完成的塊設(shè)備塊設(shè)備I/O請求,并不是所有的請求,并不是所有的I/O塊請求都可以順利的加入請求隊(duì)列塊請求都可以順利的加入請求隊(duì)列中。請求隊(duì)列中定義了自己能處理的塊設(shè)備請求限制。這些限制包中。請求隊(duì)列中定義了自己能處理的塊設(shè)備請求限制。這些限制包括:請求的最大尺寸、一個請求能夠包含的獨(dú)立段數(shù)、硬盤扇區(qū)大括:請求的最大尺寸、一個請求能夠包含的獨(dú)立段數(shù)、硬盤扇區(qū)大小等。小等。18.3.5 18.3.5 設(shè)置設(shè)置gendiskgendisk屬性中的屬性中的block

11、_device_operationsblock_device_operations結(jié)構(gòu)體結(jié)構(gòu)體在塊設(shè)備中有一個和字符設(shè)備中在塊設(shè)備中有一個和字符設(shè)備中file_operations對應(yīng)的結(jié)對應(yīng)的結(jié)構(gòu)體構(gòu)體block_device_operations。其也是一個對塊設(shè)備操作的函。其也是一個對塊設(shè)備操作的函數(shù)集合。數(shù)集合。下面對這個結(jié)構(gòu)體的主要成員進(jìn)行分析。下面對這個結(jié)構(gòu)體的主要成員進(jìn)行分析。1打開和釋放函數(shù)打開和釋放函數(shù)2I/O控制函數(shù)控制函數(shù)3介質(zhì)改變函數(shù)介質(zhì)改變函數(shù)4使介質(zhì)有效函數(shù)使介質(zhì)有效函數(shù)5獲得驅(qū)動器信息的函數(shù)獲得驅(qū)動器信息的函數(shù)6模塊指針模塊指針18.4 18.4 不使用請求隊(duì)列的

12、塊設(shè)備驅(qū)動不使用請求隊(duì)列的塊設(shè)備驅(qū)動這里,有兩個原因需要向讀者介紹不使用請求隊(duì)列的這里,有兩個原因需要向讀者介紹不使用請求隊(duì)列的塊設(shè)備驅(qū)動程序。第一個原因是,希望盡快的向讀者展現(xiàn)一塊設(shè)備驅(qū)動程序。第一個原因是,希望盡快的向讀者展現(xiàn)一個完整的塊設(shè)備驅(qū)動程序;第二個原因是,不使用請求隊(duì)列個完整的塊設(shè)備驅(qū)動程序;第二個原因是,不使用請求隊(duì)列的塊設(shè)備驅(qū)動程序相對來說,比較簡單。的塊設(shè)備驅(qū)動程序相對來說,比較簡單。18.4.1 18.4.1 不使用請求隊(duì)列的塊設(shè)備驅(qū)動程序的組不使用請求隊(duì)列的塊設(shè)備驅(qū)動程序的組成成塊設(shè)備函數(shù)驅(qū)動程序主要有一個加載函數(shù)、卸載函數(shù)和塊設(shè)備函數(shù)驅(qū)動程序主要有一個加載函數(shù)、卸載函

13、數(shù)和一個自定義的請求處理函數(shù)組成。本節(jié)將寫一個虛擬的塊設(shè)一個自定義的請求處理函數(shù)組成。本節(jié)將寫一個虛擬的塊設(shè)備驅(qū)動程序備驅(qū)動程序Virtual_blkdev。這個驅(qū)動程序在內(nèi)存中開辟了一。這個驅(qū)動程序在內(nèi)存中開辟了一個個8M的內(nèi)存空間來模擬實(shí)際的物理塊設(shè)備。這個塊設(shè)備驅(qū)動的內(nèi)存空間來模擬實(shí)際的物理塊設(shè)備。這個塊設(shè)備驅(qū)動程序代碼比較簡單,但功能卻非常強(qiáng)大。對實(shí)際物理設(shè)備的程序代碼比較簡單,但功能卻非常強(qiáng)大。對實(shí)際物理設(shè)備的操作命令同樣可以應(yīng)用在操作命令同樣可以應(yīng)用在Virtual_blkdev這個塊設(shè)備上,例如這個塊設(shè)備上,例如mkdir r、mkesfs等命令。等命令。18.4.2 18.4.

14、2 宏定義和全局變量宏定義和全局變量Virtual_blkdev塊設(shè)備驅(qū)動中定義了一些重要的宏和全塊設(shè)備驅(qū)動中定義了一些重要的宏和全局指針,包括主設(shè)備號、設(shè)備局指針,包括主設(shè)備號、設(shè)備名、名、設(shè)備的大小等。設(shè)備的大小等。18.4.3 18.4.3 加載函數(shù)加載函數(shù)Virtual_blkdev設(shè)備的加載函數(shù)主要完成分配磁盤、初設(shè)備的加載函數(shù)主要完成分配磁盤、初始化請求隊(duì)列、設(shè)置磁盤屬性和激活磁盤的工作。始化請求隊(duì)列、設(shè)置磁盤屬性和激活磁盤的工作。18.4.4 18.4.4 卸載函數(shù)卸載函數(shù)Virtual_blkdev設(shè)備的卸載函數(shù)中主要完成與設(shè)備加載設(shè)備的卸載函數(shù)中主要完成與設(shè)備加載函數(shù)中相反的

15、工作:函數(shù)中相反的工作:(1)使用)使用del_gendisk()函數(shù)刪除函數(shù)刪除gendisk設(shè)備。設(shè)備。(2)使用)使用put_disk()函數(shù)清楚函數(shù)清楚gendisk的引用計數(shù)。的引用計數(shù)。(3)使用)使用blk_cleanup_queue()函數(shù)清除請求隊(duì)列。函數(shù)清除請求隊(duì)列。18.4.5 18.4.5 自定義請求處理函數(shù)自定義請求處理函數(shù)內(nèi)核將內(nèi)核將I/O讀寫請求放入請求結(jié)構(gòu)讀寫請求放入請求結(jié)構(gòu)request中,并連接到請中,并連接到請求隊(duì)列求隊(duì)列request_queue中。因?yàn)橹?。因?yàn)閂irtual_blkdev設(shè)備是一個基于設(shè)備是一個基于內(nèi)存的設(shè)備,可以隨機(jī)讀取數(shù)據(jù),并不需要

16、復(fù)雜的內(nèi)存的設(shè)備,可以隨機(jī)讀取數(shù)據(jù),并不需要復(fù)雜的I/O調(diào)度(調(diào)度(I/O調(diào)度的作用是對請求結(jié)構(gòu)調(diào)度的作用是對請求結(jié)構(gòu)request進(jìn)行排序,最大限度的提進(jìn)行排序,最大限度的提高讀寫速率)。所以當(dāng)請求到來時,將直接使用高讀寫速率)。所以當(dāng)請求到來時,將直接使用blk_init_queue()函數(shù)中注冊的請求處理函數(shù)函數(shù)中注冊的請求處理函數(shù)Virtual_blkdev_do_request()函數(shù),對請求進(jìn)行實(shí)際的操作。這函數(shù),對請求進(jìn)行實(shí)際的操作。這里的操作就是將數(shù)據(jù)賦值的里的操作就是將數(shù)據(jù)賦值的Virtual_blkdev設(shè)備或者從設(shè)備或者從Virtual_blkdev設(shè)備中讀取數(shù)據(jù)。設(shè)備中

17、讀取數(shù)據(jù)。18.4.6 18.4.6 驅(qū)動的測試驅(qū)動的測試為了了解為了了解Virtual_blkdev這個塊設(shè)備的特性,需要對其這個塊設(shè)備的特性,需要對其進(jìn)行各方面的測試,這些測試如下所述。進(jìn)行各方面的測試,這些測試如下所述。1編譯編譯Virtual_blkdev.c文件文件2加載模塊文件加載模塊文件3lsmod查看模塊查看模塊4創(chuàng)建塊設(shè)備文件創(chuàng)建塊設(shè)備文件5在該設(shè)備上創(chuàng)建在該設(shè)備上創(chuàng)建ext2文件系統(tǒng)文件系統(tǒng)6掛載文件系統(tǒng)掛載文件系統(tǒng)7測試文件系統(tǒng)測試文件系統(tǒng)8卸載和移除設(shè)備模塊卸載和移除設(shè)備模塊18.5 I/O18.5 I/O調(diào)度器調(diào)度器Linux內(nèi)核中,內(nèi)核中,I/O調(diào)度器涉及到很多復(fù)雜

18、的數(shù)據(jù)結(jié)構(gòu),而調(diào)度器涉及到很多復(fù)雜的數(shù)據(jù)結(jié)構(gòu),而結(jié)構(gòu)之間的關(guān)系又非常復(fù)雜。要精通這些知識,遠(yuǎn)非一章一節(jié)結(jié)構(gòu)之間的關(guān)系又非常復(fù)雜。要精通這些知識,遠(yuǎn)非一章一節(jié)知識所能夠達(dá)到。但本節(jié)力圖給讀者一個清晰的概念,隨著內(nèi)知識所能夠達(dá)到。但本節(jié)力圖給讀者一個清晰的概念,隨著內(nèi)核的升級,這些概念可能有所細(xì)微的變化,但是其主要的原理核的升級,這些概念可能有所細(xì)微的變化,但是其主要的原理是基本不會變化的。在詳細(xì)講解是基本不會變化的。在詳細(xì)講解I/O調(diào)度器之前,需要知道數(shù)調(diào)度器之前,需要知道數(shù)據(jù)是怎樣從內(nèi)存到達(dá)磁盤的。據(jù)是怎樣從內(nèi)存到達(dá)磁盤的。18.5.1 18.5.1 數(shù)據(jù)從內(nèi)存到磁盤的過程數(shù)據(jù)從內(nèi)存到磁盤的過

19、程內(nèi)存是一個線性的結(jié)構(gòu),內(nèi)存是一個線性的結(jié)構(gòu),Linux系統(tǒng)將內(nèi)存分為頁。一頁系統(tǒng)將內(nèi)存分為頁。一頁最大可以是最大可以是64K,但是目前主流的系統(tǒng)頁的大小都是,但是目前主流的系統(tǒng)頁的大小都是4K?,F(xiàn)在?,F(xiàn)在假設(shè)數(shù)據(jù)存儲在內(nèi)存的相鄰幾頁中,希望將這些數(shù)據(jù)寫到磁盤假設(shè)數(shù)據(jù)存儲在內(nèi)存的相鄰幾頁中,希望將這些數(shù)據(jù)寫到磁盤上。那么每一頁的數(shù)據(jù)會被先封裝為一個段,用上。那么每一頁的數(shù)據(jù)會被先封裝為一個段,用bio_vec表示。表示。多個頁會被封裝成多個段,這些段被組成以一個多個頁會被封裝成多個段,這些段被組成以一個bio_vec為元素為元素的數(shù)組,這個數(shù)組用的數(shù)組,這個數(shù)組用bio_io_vec表示。表示

20、。18.5.2 18.5.2 塊塊I/OI/O請求請求(bio)(bio)數(shù)據(jù)從內(nèi)存到磁盤或者從磁盤到內(nèi)存的過程,叫做數(shù)據(jù)從內(nèi)存到磁盤或者從磁盤到內(nèi)存的過程,叫做I/O操操作。內(nèi)核使用一個核心數(shù)據(jù)結(jié)構(gòu)作。內(nèi)核使用一個核心數(shù)據(jù)結(jié)構(gòu)bio來描述來描述I/O操作。操作。1bio結(jié)構(gòu)體結(jié)構(gòu)體bio結(jié)構(gòu)體包含一個塊設(shè)備完成一次結(jié)構(gòu)體包含一個塊設(shè)備完成一次I/O操作所需要的一切操作所需要的一切信息。信息。2bio_vec結(jié)構(gòu)體結(jié)構(gòu)體bio中的段用中的段用bio_vec結(jié)構(gòu)體來表示。結(jié)構(gòu)體來表示。3bio結(jié)構(gòu)體的相關(guān)宏結(jié)構(gòu)體的相關(guān)宏為了程序的可移植性,在寫驅(qū)動程序時,不應(yīng)該直接的為了程序的可移植性,在寫驅(qū)動

21、程序時,不應(yīng)該直接的操作操作bio結(jié)構(gòu)和結(jié)構(gòu)和bi_io_vec數(shù)組,而應(yīng)該使用內(nèi)核開發(fā)者提供的數(shù)組,而應(yīng)該使用內(nèi)核開發(fā)者提供的一系列宏。由于在驅(qū)動中會使用這些宏,這里對其主要的宏進(jìn)一系列宏。由于在驅(qū)動中會使用這些宏,這里對其主要的宏進(jìn)行介紹。行介紹。18.5.3 18.5.3 請求結(jié)構(gòu)(請求結(jié)構(gòu)(requestrequest)幾個連續(xù)的頁面會組成一個幾個連續(xù)的頁面會組成一個bio結(jié)構(gòu),幾個相鄰的結(jié)構(gòu),幾個相鄰的bio結(jié)結(jié)構(gòu)就會組成一個請求結(jié)構(gòu)構(gòu)就會組成一個請求結(jié)構(gòu)request。這樣當(dāng)磁盤在接收一個與。這樣當(dāng)磁盤在接收一個與request對應(yīng)的命令,就不需要大幅度的移動磁頭,這樣就節(jié)對應(yīng)的命

22、令,就不需要大幅度的移動磁頭,這樣就節(jié)省了省了I/O操作的時間。操作的時間。18.5.4 18.5.4 請求隊(duì)列(請求隊(duì)列(request_queuerequest_queue)每個塊設(shè)備驅(qū)動程序都維護(hù)著自己的請求隊(duì)列每個塊設(shè)備驅(qū)動程序都維護(hù)著自己的請求隊(duì)列request_queue,其包含設(shè)備將要處理的請求鏈表。請求隊(duì)列,其包含設(shè)備將要處理的請求鏈表。請求隊(duì)列主要用來連接對同一個塊設(shè)備的多個主要用來連接對同一個塊設(shè)備的多個request請求結(jié)構(gòu)。同時請求結(jié)構(gòu)。同時請求隊(duì)列中的一些字段還保存了塊設(shè)備所支持的請求類型信請求隊(duì)列中的一些字段還保存了塊設(shè)備所支持的請求類型信息、請求的個數(shù)、段的大小、

23、硬件扇區(qū)數(shù)等與設(shè)備相關(guān)的信息、請求的個數(shù)、段的大小、硬件扇區(qū)數(shù)等與設(shè)備相關(guān)的信息。總之,內(nèi)核負(fù)責(zé)對請求隊(duì)列的正確配置,使請求隊(duì)列不息??傊瑑?nèi)核負(fù)責(zé)對請求隊(duì)列的正確配置,使請求隊(duì)列不會給塊設(shè)備發(fā)送一個不能處理的請求。會給塊設(shè)備發(fā)送一個不能處理的請求。18.5.5 18.5.5 請求隊(duì)列、請求結(jié)構(gòu)、請求隊(duì)列、請求結(jié)構(gòu)、biobio等之間的關(guān)系等之間的關(guān)系可能讀者對請求隊(duì)列可能讀者對請求隊(duì)列request_queue e、請求結(jié)構(gòu)請求結(jié)構(gòu)request、bio、bio_vec、gendisk等結(jié)構(gòu)的關(guān)系還并不清楚,除了建議讀等結(jié)構(gòu)的關(guān)系還并不清楚,除了建議讀者查閱內(nèi)核源碼外,認(rèn)真查看圖也是不錯的方

24、法。者查閱內(nèi)核源碼外,認(rèn)真查看圖也是不錯的方法。18.5.6 18.5.6 四種調(diào)度算法四種調(diào)度算法對于像磁盤這樣的塊設(shè)備來說,是不能隨機(jī)訪問數(shù)據(jù)的。在對于像磁盤這樣的塊設(shè)備來說,是不能隨機(jī)訪問數(shù)據(jù)的。在訪問實(shí)際的扇區(qū)數(shù)據(jù)以前,磁盤控制器必須花費(fèi)很多時間來尋找訪問實(shí)際的扇區(qū)數(shù)據(jù)以前,磁盤控制器必須花費(fèi)很多時間來尋找扇區(qū)的位置,如果兩個請求寫操作在磁盤中的位置相離很遠(yuǎn),那扇區(qū)的位置,如果兩個請求寫操作在磁盤中的位置相離很遠(yuǎn),那么寫操作的大部分時間將花在尋找扇區(qū)上。所以內(nèi)核需要提供一么寫操作的大部分時間將花在尋找扇區(qū)上。所以內(nèi)核需要提供一些調(diào)度方法,來使物理位置相鄰的請求盡可能先后執(zhí)行,那么就些調(diào)

25、度方法,來使物理位置相鄰的請求盡可能先后執(zhí)行,那么就可以減少尋找扇區(qū)的時間,這種調(diào)度就叫做可以減少尋找扇區(qū)的時間,這種調(diào)度就叫做I/O調(diào)度。調(diào)度。18.6 18.6 自定義自定義I/OI/O調(diào)度器調(diào)度器本節(jié)接著上一節(jié)簡介本節(jié)接著上一節(jié)簡介I/O調(diào)度器,并且仍然使用調(diào)度器,并且仍然使用Virtual_blkdev設(shè)備,只是對其進(jìn)行了一些簡單的改進(jìn),使設(shè)備,只是對其進(jìn)行了一些簡單的改進(jìn),使其效率更高。其效率更高。18.6.1 18.6.1 Virtual_blkdev塊設(shè)備的缺陷塊設(shè)備的缺陷Virtual_blkdev塊設(shè)備的數(shù)據(jù)都是存儲在內(nèi)存中的,對塊設(shè)備的數(shù)據(jù)都是存儲在內(nèi)存中的,對內(nèi)存的訪問可

26、以隨機(jī)進(jìn)行,不需要對數(shù)據(jù)進(jìn)行內(nèi)存的訪問可以隨機(jī)進(jìn)行,不需要對數(shù)據(jù)進(jìn)行I/O調(diào)度。調(diào)度。18.4節(jié)中的節(jié)中的Virtual_blkdev塊設(shè)備使用了默認(rèn)的塊設(shè)備使用了默認(rèn)的I/O調(diào)度器。調(diào)度器。實(shí)際上,對于實(shí)際上,對于Virtual_blkdev來說,一個好的來說,一個好的I/O調(diào)度器絲毫調(diào)度器絲毫起不了一點(diǎn)作用,反而會浪費(fèi)不少的起不了一點(diǎn)作用,反而會浪費(fèi)不少的CPU時間和內(nèi)存。時間和內(nèi)存。出現(xiàn)這個問題的原因是因?yàn)槌霈F(xiàn)這個問題的原因是因?yàn)镮/O調(diào)度器的原理所致。調(diào)度器的原理所致。I/O調(diào)度器試圖合并一系列的調(diào)度器試圖合并一系列的I/O請求,將相鄰的請求合并,從請求,將相鄰的請求合并,從而減少尋道

27、時間。對于內(nèi)存設(shè)備來說,這根本沒有必要,因而減少尋道時間。對于內(nèi)存設(shè)備來說,這根本沒有必要,因?yàn)閮?nèi)存設(shè)備根本不需要所謂的尋道時間,它讀取各個位置的為內(nèi)存設(shè)備根本不需要所謂的尋道時間,它讀取各個位置的塊的時間幾乎相等。本節(jié)將通過自定義塊的時間幾乎相等。本節(jié)將通過自定義I/O調(diào)度器的方法,調(diào)度器的方法,將其屏蔽掉。將其屏蔽掉。18.6.2 18.6.2 指定指定noop調(diào)度器調(diào)度器linux內(nèi)核中包含內(nèi)核中包含4個個I/O調(diào)度器:調(diào)度器:Anticipatory、CFQ、Deadline和和Noop。2.6.18之前的之前的linux默認(rèn)使用默認(rèn)使用anticipatory,而,而之后的默認(rèn)使用之

28、后的默認(rèn)使用cfq。關(guān)于這。關(guān)于這4個調(diào)度器的原理已經(jīng)在上一節(jié)做個調(diào)度器的原理已經(jīng)在上一節(jié)做過介紹,這里不重復(fù)講述。這里主要用到的是過介紹,這里不重復(fù)講述。這里主要用到的是Noop調(diào)度器。調(diào)度器。Noop調(diào)度器是一個基本上不錯任何事情的空調(diào)度器,它直接將調(diào)度器是一個基本上不錯任何事情的空調(diào)度器,它直接將I/O請求傳遞給通用塊層,告訴通用塊層已經(jīng)對請求做了相應(yīng)的請求傳遞給通用塊層,告訴通用塊層已經(jīng)對請求做了相應(yīng)的調(diào)度處理。調(diào)度處理。18.6.3 18.6.3 Virtual_blkdev的改進(jìn)實(shí)例的改進(jìn)實(shí)例18.4節(jié)的節(jié)的Virtual_blkdev使用了默認(rèn)的調(diào)度算法,但是使用了默認(rèn)的調(diào)度算法

29、,但是并不符合內(nèi)存設(shè)備的要求,這里對并不符合內(nèi)存設(shè)備的要求,這里對Virtual_blkdev_init()函數(shù)函數(shù)進(jìn)行了簡單的修改,使用進(jìn)行了簡單的修改,使用noop調(diào)度算法取代了默認(rèn)的調(diào)度算調(diào)度算法取代了默認(rèn)的調(diào)度算法。法。18.6.4 18.6.4 編譯和編譯和測試測試本節(jié)對本節(jié)對Virtual_blkdev的修改非常少,但是已經(jīng)使的修改非常少,但是已經(jīng)使Virtual_blkdev的效率提高了不少。使用和的效率提高了不少。使用和18.4節(jié)一樣的編節(jié)一樣的編譯方法編譯新的譯方法編譯新的Virtual_blkdev模塊,模塊,make命令如下所示。命令如下所示。18.7 18.7 脫離脫離

30、I/OI/O調(diào)度器調(diào)度器為了使讀者詳細(xì)的了解內(nèi)核是怎么對數(shù)據(jù)進(jìn)行讀寫的,為了使讀者詳細(xì)的了解內(nèi)核是怎么對數(shù)據(jù)進(jìn)行讀寫的,這里對通用塊層的函數(shù)調(diào)用關(guān)系進(jìn)行了仔細(xì)分析。本節(jié)試圖這里對通用塊層的函數(shù)調(diào)用關(guān)系進(jìn)行了仔細(xì)分析。本節(jié)試圖拜托繁瑣的拜托繁瑣的I/O調(diào)度器,對數(shù)據(jù)讀寫的本質(zhì)進(jìn)行分析,通過這調(diào)度器,對數(shù)據(jù)讀寫的本質(zhì)進(jìn)行分析,通過這種本質(zhì)的學(xué)習(xí)讀者將對數(shù)據(jù)讀寫的整個流程有一個深刻的理種本質(zhì)的學(xué)習(xí)讀者將對數(shù)據(jù)讀寫的整個流程有一個深刻的理解。首先,將從請求隊(duì)列中的解。首先,將從請求隊(duì)列中的bio處理函數(shù)開始。處理函數(shù)開始。18.7.1 18.7.1 請求隊(duì)列中的請求隊(duì)列中的biobio處理函數(shù)處理函數(shù)

31、盡管上一節(jié)的盡管上一節(jié)的noop調(diào)度器已經(jīng)相當(dāng)簡單。它除了告訴調(diào)度器已經(jīng)相當(dāng)簡單。它除了告訴內(nèi)核一個內(nèi)核一個bio已經(jīng)調(diào)度完成,正在等待處理之外,幾乎什么已經(jīng)調(diào)度完成,正在等待處理之外,幾乎什么都不做。許多程序員錯誤的以為都不做。許多程序員錯誤的以為noop調(diào)度器的效率很高,是調(diào)度器的效率很高,是的,它確實(shí)比其他三種調(diào)度器效率要高,但是有比的,它確實(shí)比其他三種調(diào)度器效率要高,但是有比noop調(diào)度調(diào)度器效率更高的方法,那就是不用器效率更高的方法,那就是不用I/O調(diào)度器。調(diào)度器。18.7.2 18.7.2 通用塊層函數(shù)調(diào)用關(guān)系通用塊層函數(shù)調(diào)用關(guān)系有了上面關(guān)于請求隊(duì)列的基礎(chǔ)知識后,將分析一個塊有了上

32、面關(guān)于請求隊(duì)列的基礎(chǔ)知識后,將分析一個塊設(shè)備的讀寫過程。設(shè)備的讀寫過程。1通用塊層函數(shù)調(diào)用關(guān)系通用塊層函數(shù)調(diào)用關(guān)系2使用使用I/O調(diào)度器和不使用調(diào)度器和不使用I/O調(diào)度器的分析調(diào)度器的分析3使用使用I/O調(diào)度器和不使用調(diào)度器和不使用I/O調(diào)度器的效率分析調(diào)度器的效率分析18.7.3 18.7.3 對對Virtual_blkdevVirtual_blkdev塊設(shè)備的改進(jìn)塊設(shè)備的改進(jìn)對對Virtual_blkdev塊設(shè)備的改進(jìn),首先需要修改塊設(shè)備的改進(jìn),首先需要修改Virtual_blkdev_init()函數(shù),使其使用自定義的制造請求函數(shù),函數(shù),使其使用自定義的制造請求函數(shù),修改后的代碼如下所示

33、:修改后的代碼如下所示:1Virtual_blkdev_init()函數(shù)的修改函數(shù)的修改2請求制造函數(shù)請求制造函數(shù)Virtual_blkdev_make_request()18.7.4 18.7.4 編譯和測試編譯和測試使用使用make命令對新的命令對新的Virtual_blkdev塊設(shè)備進(jìn)行編譯,塊設(shè)備進(jìn)行編譯,命令如下。命令如下。18.8 18.8 塊設(shè)備的物理結(jié)構(gòu)塊設(shè)備的物理結(jié)構(gòu)上幾節(jié)介紹的塊設(shè)備,其基本功能還不完善。本節(jié)將上幾節(jié)介紹的塊設(shè)備,其基本功能還不完善。本節(jié)將塊設(shè)備的物理結(jié)構(gòu)進(jìn)行完善,首先介紹分區(qū)。塊設(shè)備的物理結(jié)構(gòu)進(jìn)行完善,首先介紹分區(qū)。18.8.1 18.8.1 為為Virt

34、ual_blkdevVirtual_blkdev塊設(shè)備添加分區(qū)塊設(shè)備添加分區(qū)對于實(shí)際的物理磁盤,一般都有多個分區(qū),本節(jié)將對對于實(shí)際的物理磁盤,一般都有多個分區(qū),本節(jié)將對Virtual_blkdev設(shè)備進(jìn)行分區(qū),分區(qū)的概念是:設(shè)備進(jìn)行分區(qū),分區(qū)的概念是:1分區(qū)分區(qū)分區(qū)是物理磁盤的一部分,將物理磁盤分為幾個單獨(dú)分區(qū)是物理磁盤的一部分,將物理磁盤分為幾個單獨(dú)的單元,每一個單元就是一個分區(qū)。每一個分區(qū)可以用來存的單元,每一個單元就是一個分區(qū)。每一個分區(qū)可以用來存放文件和數(shù)據(jù)。放文件和數(shù)據(jù)。2alloc_disk()函數(shù)增加分區(qū)函數(shù)增加分區(qū)比起比起I/O調(diào)度來,對磁盤進(jìn)行分區(qū)則非常容易,因?yàn)閮?nèi)調(diào)度來,對

35、磁盤進(jìn)行分區(qū)則非常容易,因?yàn)閮?nèi)核做了大部分的工作。這些工作大都由核做了大部分的工作。這些工作大都由fs/partitions目錄中的目錄中的文件來完成。文件來完成。18.8.2 18.8.2 對新的對新的Virtual_blkdevVirtual_blkdev代碼的分析代碼的分析只要對只要對18.7節(jié)中的代碼做一點(diǎn)簡單的修改,就能夠使設(shè)節(jié)中的代碼做一點(diǎn)簡單的修改,就能夠使設(shè)備支持分區(qū)。首先在文件開始添加一個分區(qū)數(shù)目的宏,代碼備支持分區(qū)。首先在文件開始添加一個分區(qū)數(shù)目的宏,代碼如下所示。如下所示。18.8.3 18.8.3 編譯和測試編譯和測試在使用在使用Virtual_blkdev設(shè)備前,需要

36、先編譯和調(diào)試代碼,設(shè)備前,需要先編譯和調(diào)試代碼,這些步驟如下所示:這些步驟如下所示:1編譯代碼編譯代碼2加載模塊加載模塊3分區(qū)分區(qū)4測試分區(qū)數(shù)測試分區(qū)數(shù)18.8.4 18.8.4 分區(qū)數(shù)的計算分區(qū)數(shù)的計算一個磁盤的最大分區(qū)數(shù)目由兩方面決定,第一是一個磁盤的最大分區(qū)數(shù)目由兩方面決定,第一是alloc_gendisk()函數(shù)中指定的最大分區(qū)數(shù),第二是磁盤的物函數(shù)中指定的最大分區(qū)數(shù),第二是磁盤的物理磁道數(shù)。在上述的理磁道數(shù)。在上述的Virtual_blkdev塊設(shè)備的代碼中,并沒塊設(shè)備的代碼中,并沒有為磁盤指定磁道數(shù),這樣情況下,有為磁盤指定磁道數(shù),這樣情況下,Linux內(nèi)核只能猜測磁內(nèi)核只能猜測磁盤的磁道數(shù)。盤的磁道數(shù)。18.8.5 18.8.5 設(shè)置設(shè)置Vir

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論