




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
第18章塊設(shè)備驅(qū)動程序除了字符設(shè)備、網(wǎng)絡(luò)設(shè)備外,Linux系統(tǒng)中還有塊設(shè)備。字符設(shè)備和塊設(shè)備在內(nèi)核中的結(jié)構(gòu)有很大的不同,總體來說,塊設(shè)備要比字符設(shè)備復(fù)雜很多。塊設(shè)備主要包含磁盤設(shè)備、SD卡等,這些設(shè)備是Linux系統(tǒng)中不可缺少的存儲設(shè)備。計算機中都需要這樣的設(shè)備來存儲數(shù)據(jù),所以學(xué)會塊設(shè)備驅(qū)動程序的寫法是非常重要的。18.1塊設(shè)備簡介本節(jié)對塊設(shè)備的相關(guān)概念進行了簡要的分析。理解這些概念對寫塊設(shè)備驅(qū)動程序具有十分重要的意義。18.1.1塊設(shè)備總體概述Linux內(nèi)核中,I/O設(shè)備大致分為兩類:塊設(shè)備和字符設(shè)備。塊設(shè)備將信息存儲在固定大小的塊中,每個塊都有自己的地址。數(shù)據(jù)塊的大小通常在512字節(jié)到4K字節(jié)之間。塊設(shè)備的基本特征是每個塊都能獨立于其它塊而讀寫。磁盤就是最常見的塊設(shè)備。在Linux內(nèi)核中,塊設(shè)備與內(nèi)核其他模塊的關(guān)系如圖所示:18.1.2塊設(shè)備的結(jié)構(gòu)在寫塊設(shè)備驅(qū)動程序之前,了解典型塊設(shè)備的結(jié)構(gòu)是非常重要的。圖顯示的是磁盤的一個盤面,一些重要的概念將在下面講述。18.2塊設(shè)備驅(qū)動程序的架構(gòu)相對于字符設(shè)備來說,塊設(shè)備的驅(qū)動程序架構(gòu)要稍微復(fù)雜一些,其中涉及到很多重要的概念。對這些概念的理解是編寫驅(qū)動程序的前提,本節(jié)將對塊設(shè)備的整體架構(gòu)進行詳細(xì)講解。18.2.1塊設(shè)備加載過程在塊設(shè)備的模塊加載函數(shù)中,需要完成的一些重要工作,這些工作涉及到的一些重要概念,將在后面的小節(jié)中進行講解,本節(jié)的目的是為了給出一個整體的概念。塊設(shè)備驅(qū)動加載模塊中需要完成的工作如下圖所示:18.2.2塊設(shè)備卸載過程在塊設(shè)備驅(qū)動的卸載模塊中完成與模塊加載函數(shù)相反的工作。(1)使用del_gendisk()函數(shù)刪除gendisk設(shè)備,并使用put_disk()函數(shù)刪除對gendisk設(shè)備的引用。(2)使用blk_cleanup_queue()函數(shù)清除請求隊列,并釋放請求隊列所占用的資源。(3)如果在模塊加載函數(shù)中使用了register_blkdev()注冊設(shè)備,那么需要在模塊卸載函數(shù)中使用unregister_blkdev()函數(shù)注銷塊設(shè)備,并釋放對塊設(shè)備的引用。18.3通用塊層通用塊層是塊設(shè)備驅(qū)動的核心部分,這部分主要包含塊設(shè)備驅(qū)動程序的通用代碼部分。本節(jié)將介紹通用塊層的主要函數(shù)和數(shù)據(jù)結(jié)構(gòu)。18.3.1通用塊層通用塊層是一個內(nèi)核組件,它處理來自系統(tǒng)其他組件發(fā)出的塊設(shè)備請求。換句話說,通用塊層包含了塊設(shè)備操作的一些通用函數(shù)和數(shù)據(jù)結(jié)構(gòu)。圖是塊設(shè)備加載函數(shù)中用到的一些重要數(shù)據(jù)結(jié)構(gòu),如通用磁盤結(jié)構(gòu)gendisk、請求隊列結(jié)構(gòu)request_queue、請求結(jié)構(gòu)request、塊設(shè)備I/O操作結(jié)構(gòu)bio、塊設(shè)備操作結(jié)構(gòu)block_device_operations等。這些結(jié)構(gòu)將在下面的幾小節(jié)詳細(xì)簡述。18.3.2alloc_disk()函數(shù)對應(yīng)的gendisk結(jié)構(gòu)體現(xiàn)實生活中有許多具體的物理塊設(shè)備,例如磁盤、光盤等。不同的物理塊設(shè)備其結(jié)構(gòu)是不一樣的,為了將這些塊設(shè)備公用屬性在內(nèi)核中統(tǒng)一,內(nèi)核開發(fā)者定義了一個gendisk結(jié)構(gòu)體來描述磁盤。gendisk是generaldisk的簡稱,一般稱為通用磁盤。18.3.3塊設(shè)備的注冊和注銷為了使內(nèi)核知道塊設(shè)備的存在,需要使用塊設(shè)備注冊函數(shù)。在不使用塊設(shè)備時,也需要注銷塊設(shè)備。塊設(shè)備的注冊和注銷如下所述:1.注冊塊設(shè)備函數(shù)register_blkdev()2.注銷塊設(shè)備函數(shù)unregister_blkdev()18.3.4請求隊列簡單的講,一個塊設(shè)備的請求隊列就是包含塊設(shè)備I/O請求的一個隊列。這個隊列使用鏈表線性的排列。請求隊列中存儲未完成的塊設(shè)備I/O請求,并不是所有的I/O塊請求都可以順利的加入請求隊列中。請求隊列中定義了自己能處理的塊設(shè)備請求限制。這些限制包括:請求的最大尺寸、一個請求能夠包含的獨立段數(shù)、硬盤扇區(qū)大小等。18.3.5設(shè)置gendisk屬性中的block_device_operations結(jié)構(gòu)體在塊設(shè)備中有一個和字符設(shè)備中file_operations對應(yīng)的結(jié)構(gòu)體block_device_operations。其也是一個對塊設(shè)備操作的函數(shù)集合。下面對這個結(jié)構(gòu)體的主要成員進行分析。1.打開和釋放函數(shù)2.I/O控制函數(shù)3.介質(zhì)改變函數(shù)4.使介質(zhì)有效函數(shù)5.獲得驅(qū)動器信息的函數(shù)6.模塊指針18.4不使用請求隊列的塊設(shè)備驅(qū)動這里,有兩個原因需要向讀者介紹不使用請求隊列的塊設(shè)備驅(qū)動程序。第一個原因是,希望盡快的向讀者展現(xiàn)一個完整的塊設(shè)備驅(qū)動程序;第二個原因是,不使用請求隊列的塊設(shè)備驅(qū)動程序相對來說,比較簡單。18.4.1不使用請求隊列的塊設(shè)備驅(qū)動程序的組成塊設(shè)備函數(shù)驅(qū)動程序主要有一個加載函數(shù)、卸載函數(shù)和一個自定義的請求處理函數(shù)組成。本節(jié)將寫一個虛擬的塊設(shè)備驅(qū)動程序Virtual_blkdev。這個驅(qū)動程序在內(nèi)存中開辟了一個8M的內(nèi)存空間來模擬實際的物理塊設(shè)備。這個塊設(shè)備驅(qū)動程序代碼比較簡單,但功能卻非常強大。對實際物理設(shè)備的操作命令同樣可以應(yīng)用在Virtual_blkdev這個塊設(shè)備上,例如mkdir、mkesfs等命令。18.4.2宏定義和全局變量Virtual_blkdev塊設(shè)備驅(qū)動中定義了一些重要的宏和全局指針,包括主設(shè)備號、設(shè)備名、設(shè)備的大小等。18.4.3加載函數(shù)Virtual_blkdev設(shè)備的加載函數(shù)主要完成分配磁盤、初始化請求隊列、設(shè)置磁盤屬性和激活磁盤的工作。18.4.4卸載函數(shù)Virtual_blkdev設(shè)備的卸載函數(shù)中主要完成與設(shè)備加載函數(shù)中相反的工作:(1)使用del_gendisk()函數(shù)刪除gendisk設(shè)備。(2)使用put_disk()函數(shù)清楚gendisk的引用計數(shù)。(3)使用blk_cleanup_queue()函數(shù)清除請求隊列。18.4.5自定義請求處理函數(shù)內(nèi)核將I/O讀寫請求放入請求結(jié)構(gòu)request中,并連接到請求隊列request_queue中。因為Virtual_blkdev設(shè)備是一個基于內(nèi)存的設(shè)備,可以隨機讀取數(shù)據(jù),并不需要復(fù)雜的I/O調(diào)度(I/O調(diào)度的作用是對請求結(jié)構(gòu)request進行排序,最大限度的提高讀寫速率)。所以當(dāng)請求到來時,將直接使用blk_init_queue()函數(shù)中注冊的請求處理函數(shù)Virtual_blkdev_do_request()函數(shù),對請求進行實際的操作。這里的操作就是將數(shù)據(jù)賦值的Virtual_blkdev設(shè)備或者從Virtual_blkdev設(shè)備中讀取數(shù)據(jù)。18.4.6驅(qū)動的測試為了了解Virtual_blkdev這個塊設(shè)備的特性,需要對其進行各方面的測試,這些測試如下所述。1.編譯Virtual_blkdev.c文件2.加載模塊文件3.lsmod查看模塊4.創(chuàng)建塊設(shè)備文件5.在該設(shè)備上創(chuàng)建ext2文件系統(tǒng)6.掛載文件系統(tǒng)7.測試文件系統(tǒng)8.卸載和移除設(shè)備模塊18.5I/O調(diào)度器Linux內(nèi)核中,I/O調(diào)度器涉及到很多復(fù)雜的數(shù)據(jù)結(jié)構(gòu),而結(jié)構(gòu)之間的關(guān)系又非常復(fù)雜。要精通這些知識,遠(yuǎn)非一章一節(jié)知識所能夠達到。但本節(jié)力圖給讀者一個清晰的概念,隨著內(nèi)核的升級,這些概念可能有所細(xì)微的變化,但是其主要的原理是基本不會變化的。在詳細(xì)講解I/O調(diào)度器之前,需要知道數(shù)據(jù)是怎樣從內(nèi)存到達磁盤的。18.5.1數(shù)據(jù)從內(nèi)存到磁盤的過程內(nèi)存是一個線性的結(jié)構(gòu),Linux系統(tǒng)將內(nèi)存分為頁。一頁最大可以是64K,但是目前主流的系統(tǒng)頁的大小都是4K?,F(xiàn)在假設(shè)數(shù)據(jù)存儲在內(nèi)存的相鄰幾頁中,希望將這些數(shù)據(jù)寫到磁盤上。那么每一頁的數(shù)據(jù)會被先封裝為一個段,用bio_vec表示。多個頁會被封裝成多個段,這些段被組成以一個bio_vec為元素的數(shù)組,這個數(shù)組用bio_io_vec表示。18.5.2塊I/O請求(bio)數(shù)據(jù)從內(nèi)存到磁盤或者從磁盤到內(nèi)存的過程,叫做I/O操作。內(nèi)核使用一個核心數(shù)據(jù)結(jié)構(gòu)bio來描述I/O操作。1.bio結(jié)構(gòu)體bio結(jié)構(gòu)體包含一個塊設(shè)備完成一次I/O操作所需要的一切信息。2.bio_vec結(jié)構(gòu)體bio中的段用bio_vec結(jié)構(gòu)體來表示。3.bio結(jié)構(gòu)體的相關(guān)宏為了程序的可移植性,在寫驅(qū)動程序時,不應(yīng)該直接的操作bio結(jié)構(gòu)和bi_io_vec數(shù)組,而應(yīng)該使用內(nèi)核開發(fā)者提供的一系列宏。由于在驅(qū)動中會使用這些宏,這里對其主要的宏進行介紹。18.5.3請求結(jié)構(gòu)(request)幾個連續(xù)的頁面會組成一個bio結(jié)構(gòu),幾個相鄰的bio結(jié)構(gòu)就會組成一個請求結(jié)構(gòu)request。這樣當(dāng)磁盤在接收一個與request對應(yīng)的命令,就不需要大幅度的移動磁頭,這樣就節(jié)省了I/O操作的時間。18.5.4請求隊列(request_queue)每個塊設(shè)備驅(qū)動程序都維護著自己的請求隊列request_queue,其包含設(shè)備將要處理的請求鏈表。請求隊列主要用來連接對同一個塊設(shè)備的多個request請求結(jié)構(gòu)。同時請求隊列中的一些字段還保存了塊設(shè)備所支持的請求類型信息、請求的個數(shù)、段的大小、硬件扇區(qū)數(shù)等與設(shè)備相關(guān)的信息。總之,內(nèi)核負(fù)責(zé)對請求隊列的正確配置,使請求隊列不會給塊設(shè)備發(fā)送一個不能處理的請求。18.5.5請求隊列、請求結(jié)構(gòu)、bio等之間的關(guān)系可能讀者對請求隊列request_queue、請求結(jié)構(gòu)request、bio、bio_vec、gendisk等結(jié)構(gòu)的關(guān)系還并不清楚,除了建議讀者查閱內(nèi)核源碼外,認(rèn)真查看圖也是不錯的方法。18.5.6四種調(diào)度算法對于像磁盤這樣的塊設(shè)備來說,是不能隨機訪問數(shù)據(jù)的。在訪問實際的扇區(qū)數(shù)據(jù)以前,磁盤控制器必須花費很多時間來尋找扇區(qū)的位置,如果兩個請求寫操作在磁盤中的位置相離很遠(yuǎn),那么寫操作的大部分時間將花在尋找扇區(qū)上。所以內(nèi)核需要提供一些調(diào)度方法,來使物理位置相鄰的請求盡可能先后執(zhí)行,那么就可以減少尋找扇區(qū)的時間,這種調(diào)度就叫做I/O調(diào)度。18.6自定義I/O調(diào)度器本節(jié)接著上一節(jié)簡介I/O調(diào)度器,并且仍然使用Virtual_blkdev設(shè)備,只是對其進行了一些簡單的改進,使其效率更高。18.6.1Virtual_blkdev塊設(shè)備的缺陷Virtual_blkdev塊設(shè)備的數(shù)據(jù)都是存儲在內(nèi)存中的,對內(nèi)存的訪問可以隨機進行,不需要對數(shù)據(jù)進行I/O調(diào)度。18.4節(jié)中的Virtual_blkdev塊設(shè)備使用了默認(rèn)的I/O調(diào)度器。實際上,對于Virtual_blkdev來說,一個好的I/O調(diào)度器絲毫起不了一點作用,反而會浪費不少的CPU時間和內(nèi)存。出現(xiàn)這個問題的原因是因為I/O調(diào)度器的原理所致。I/O調(diào)度器試圖合并一系列的I/O請求,將相鄰的請求合并,從而減少尋道時間。對于內(nèi)存設(shè)備來說,這根本沒有必要,因為內(nèi)存設(shè)備根本不需要所謂的尋道時間,它讀取各個位置的塊的時間幾乎相等。本節(jié)將通過自定義I/O調(diào)度器的方法,將其屏蔽掉。18.6.2指定noop調(diào)度器linux內(nèi)核中包含4個I/O調(diào)度器:Anticipatory、CFQ、Deadline和Noop。2.6.18之前的linux默認(rèn)使用anticipatory,而之后的默認(rèn)使用cfq。關(guān)于這4個調(diào)度器的原理已經(jīng)在上一節(jié)做過介紹,這里不重復(fù)講述。這里主要用到的是Noop調(diào)度器。Noop調(diào)度器是一個基本上不錯任何事情的空調(diào)度器,它直接將I/O請求傳遞給通用塊層,告訴通用塊層已經(jīng)對請求做了相應(yīng)的調(diào)度處理。18.6.3Virtual_blkdev的改進實例18.4節(jié)的Virtual_blkdev使用了默認(rèn)的調(diào)度算法,但是并不符合內(nèi)存設(shè)備的要求,這里對Virtual_blkdev_init()函數(shù)進行了簡單的修改,使用noop調(diào)度算法取代了默認(rèn)的調(diào)度算法。18.6.4編譯和測試本節(jié)對Virtual_blkdev的修改非常少,但是已經(jīng)使Virtual_blkdev的效率提高了不少。使用和18.4節(jié)一樣的編譯方法編譯新的Virtual_blkdev模塊,make命令如下所示。18.7脫離I/O調(diào)度器為了使讀者詳細(xì)的了解內(nèi)核是怎么對數(shù)據(jù)進行讀寫的,這里對通用塊層的函數(shù)調(diào)用關(guān)系進行了仔細(xì)分析。本節(jié)試圖拜托繁瑣的I/O調(diào)度器,對數(shù)據(jù)讀寫的本質(zhì)進行分析,通過這種本質(zhì)的學(xué)習(xí)讀者將對數(shù)據(jù)讀寫的整個流程有一個深刻的理解。首先,將從請求隊列中的bio處理函數(shù)開始。18.7.1請求隊列中的bio處理函數(shù)盡管上一節(jié)的noop調(diào)度器已經(jīng)相當(dāng)簡單。它除了告訴內(nèi)核一個bio已經(jīng)調(diào)度完成,正在等待處理之外,幾乎什么都不做。許多程序員錯誤的以為noop調(diào)度器的效率很高,是的,它確實比其他三種調(diào)度器效率要高,但是有比noop調(diào)度器效率更高的方法,那就是不用I/O調(diào)度器。18.7.2通用塊層函數(shù)調(diào)用關(guān)系有了上面關(guān)于請求隊列的基礎(chǔ)知識后,將分析一個塊設(shè)備的讀寫過程。1.通用塊層函數(shù)調(diào)用關(guān)系2.使用I/O調(diào)度器和不使用I/O調(diào)度器的分析3.使用I/O調(diào)度器和不使用I/O調(diào)度器的效率分析18.7.3對Virtual_blkdev塊設(shè)備的改進對Virtual_blkdev塊設(shè)備的改進,首先需要修改Virtual_blkdev_init()函數(shù),使其使用自定義的制造請求函數(shù),修改后的代碼如下所示:1.Virtual_blkdev_init()函數(shù)的修改2.請求制造函數(shù)Virtual_blkdev_make_request()18.7.4編譯和測試使用make命令對新的Virtual_blkdev塊設(shè)備進行編譯,命令如下。18.8塊設(shè)備的物理結(jié)構(gòu)上幾節(jié)介紹的塊設(shè)備,其基本功能還不完善。本節(jié)將塊設(shè)備的物理結(jié)構(gòu)進行完善,首先介紹分區(qū)。18.8.1為Virtual_blkdev塊設(shè)備添加分區(qū)對于實際的物理磁盤,一般都有多個分區(qū),本節(jié)將對Virtual_blkdev設(shè)備進行分區(qū),分區(qū)的概念是:1.分區(qū)分區(qū)是物理磁盤的一部分,將物理磁盤分為幾個單獨的單元,每一個單元就是一個分區(qū)。每一個分區(qū)可以用來存放文件和數(shù)據(jù)。2.a(chǎn)lloc_disk()函數(shù)增加分區(qū)比起I/O調(diào)度來,對磁盤進行分區(qū)則非常容易,因為內(nèi)核做了大部分的工作。這些工作大都由fs/partitions目錄中的文件來完成。18.8.2對新的Virtual_blkdev代碼的分析只要對18.7節(jié)中的代碼做一點簡單的修改,就能夠使設(shè)備支持分區(qū)。首先在文件開始添加一個分區(qū)數(shù)目的宏,代碼如下所示。18.8.3編譯和測試在使用Virtual_blkdev設(shè)備前,需要先編譯和調(diào)試代碼,這些步驟如下所示:1.編譯代碼2.加載模塊3.分區(qū)4.測試分區(qū)數(shù)18.8.4分區(qū)數(shù)的計算一個磁盤的最大分區(qū)數(shù)目由兩方面決定,第一是alloc_gendisk()函數(shù)中指定的最大分區(qū)數(shù),第二是磁盤的物理磁道數(shù)。在上述的Virtual_blkdev塊設(shè)備的代碼中,并沒有為磁盤指定磁道數(shù),這樣情況下,
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 精果園優(yōu)高效栽培集成技術(shù)
- 皖北砂姜黑土產(chǎn)能提升技術(shù)
- 鐵路工程信息模型實體繼承關(guān)系、典型數(shù)據(jù)模式拓展
- 血沉(ESR)的檢測及臨床意義2025
- 2024年CPMM知識梳理試題及答案
- 2025年高純氧化鋁絕緣材料項目發(fā)展計劃
- 2025年專用小麥新品種合作協(xié)議書
- 物流師考試必看試題及答案
- 解析2024年CPSM試題變化試題及答案
- 人體內(nèi)分泌系統(tǒng)的調(diào)節(jié)機制試題及答案
- 高中高考補寫句子公開課一等獎?wù)n件省賽課獲獎?wù)n件
- 文獻檢索教學(xué)大綱
- 針刺傷的防范應(yīng)急預(yù)案
- 2016年初級護師考試《相關(guān)專業(yè)知識》真題及答案
- 特種設(shè)備日管控、周排查、月調(diào)度模板
- 中醫(yī)基礎(chǔ)理論教學(xué)講稿
- 硫磺安全技術(shù)說明書MSDS
- 重癥專科護士考試題庫(含答案)
- 應(yīng)急燈、出口指示燈、消防栓、滅火器點檢表
- 綜合管理中心組織架構(gòu)圖人員編制表及崗位說明書
- 數(shù)字化轉(zhuǎn)型對商業(yè)銀行盈利能力影響的研究
評論
0/150
提交評論