虛擬塊設(shè)備驅(qū)動程序設(shè)計與分析_第1頁
虛擬塊設(shè)備驅(qū)動程序設(shè)計與分析_第2頁
虛擬塊設(shè)備驅(qū)動程序設(shè)計與分析_第3頁
虛擬塊設(shè)備驅(qū)動程序設(shè)計與分析_第4頁
虛擬塊設(shè)備驅(qū)動程序設(shè)計與分析_第5頁
已閱讀5頁,還剩10頁未讀 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、如果只是為了應(yīng)付考試,這個文檔就太啰嗦了,不用看,不過還是可以幫助記憶,考試只會考其中加粗字體的幾個函數(shù)中的一個,至于是 哪個我不能斷定,因此要記的還是比較多的,要是能理解就更好了,結(jié)合課本和下面的解釋應(yīng)該能大體上弄明白這個虛擬塊設(shè)備驅(qū)動的 實現(xiàn)過程, 畢竟設(shè)備驅(qū)動是內(nèi)核的一部分, 光看下面的解釋也是還是很頭暈的, 不過堅持看下去還是有收獲的, 我也差不多花了半天時間, 不過,要是打算的話就可以直接跳過了。#define MAJOR_NR 70 /我們創(chuàng)造的虛擬塊設(shè)備的主設(shè)備號#define DEVICE_NAME “bdemo”/我們創(chuàng)造的虛擬塊設(shè)備的名字,當(dāng)設(shè)備加載成功后可用 lsmod

2、命令查看到該設(shè)備模塊名 #define blkdemo_devs 2 /虛擬塊設(shè)備的個數(shù)#define blkdemo_rahead 2 /讀取塊設(shè)備時預(yù)讀的扇區(qū)個數(shù)#define blkdemo_size 4 /每個虛擬塊設(shè)備的大小,單位為 KB#define blkdemo_blksize 1024 /設(shè)備每個數(shù)據(jù)塊的大小,即 block ,單位為字節(jié)#define blkdemo_hardsect 512 /設(shè)備每個扇區(qū)的大小,單位為字節(jié)struct blkdemo_device / 這里定義了我們將要創(chuàng)造的虛擬塊設(shè)備的數(shù)據(jù)結(jié)構(gòu)intsize; / 用來記錄真實塊設(shè)備的容量,即下面 da

3、ta 指針所指向數(shù)據(jù)存儲區(qū)的大小intuse_cnt; / 用來記錄正在使用該塊設(shè)備的程序的個數(shù)inthardsect; / 用來保存該塊設(shè)備每個扇區(qū)的大小,單位為字節(jié),即設(shè)備的使用計數(shù)u8*data; / 該指針所指向的內(nèi)存區(qū)域就是該塊設(shè)備真正用來存儲數(shù)據(jù)的區(qū)域,在該設(shè)備還未被加載函數(shù)初始化時,該指針為 / 空,即系統(tǒng)還沒有為該設(shè)備分配內(nèi)存區(qū)域。;static int blkdemo_sizesblkdemo_devs; /用來保存我們創(chuàng)建的所有虛擬塊設(shè)備的大小,單位為 KBstatic int blkdemo_blksizesblkdemo_devs; /用來保存我們創(chuàng)建的所有虛擬塊設(shè)備中

4、每個數(shù)據(jù)塊的大小,單位為字節(jié) static int blkdemo_hardsectsblkdemo_devs;/用來保存我們創(chuàng)建的所有虛擬塊設(shè)備中每個扇區(qū)的大小,單位為字節(jié)/上面的這三個數(shù)組將會在我們加載這些設(shè)備時被注冊到內(nèi)核的數(shù)據(jù)結(jié)構(gòu)中 (即讓內(nèi)核中與之相關(guān)的一些指針指向它們, 讓內(nèi)核能夠讀取 我們所創(chuàng)建的設(shè)備的一些重要信息/對于一個新的設(shè)備,內(nèi)核肯定不知道他為何物,要想讓內(nèi)核識別我們自己創(chuàng)造的設(shè)備,則必須將該設(shè)備的一些信息、使用這個設(shè)備的方 /法等告訴內(nèi)核, 由于內(nèi)核早已編譯成型, 至于如何去告訴內(nèi)核就早已模式化。 內(nèi)核中有幾個指針數(shù)組 (書本 page81 專門用來完成上面 的部分任務(wù)

5、:/ blk_size;/ blksize_size;/ hardsect_size;/ read_ahead;/這幾個數(shù)組都為每一個主設(shè)備號留有一個位置,對于 2.4的內(nèi)核,主設(shè)備號和次設(shè)備號均用 8位二進制來表示(即短整型的高八位和 /低八位 ,因此這幾個數(shù)組都包含有 256個元素,每個元素都是與主設(shè)備號對應(yīng)的一個指針,如果主設(shè)備號所對應(yīng)的設(shè)備不存在,則該 /指針置為空 (NULL,其實其中很多指針都為空,因為一般電腦上都沒有那么多不同類型的塊設(shè)備,當(dāng)然,對于我們所創(chuàng)造的這個塊設(shè) /備而言,它與系統(tǒng)中所存在的其他塊設(shè)備的類型都不同,要為其確定一個主設(shè)備號,這個沒什么硬性的規(guī)定,只要找一個沒

6、被使用的主 /設(shè)備號就可以了,這個程序中使用的是 70(前面的 MOJOR_NR宏 。上面我們定義了保存有虛擬塊設(shè)備信息的數(shù)組,現(xiàn)在只要將他們的 /首地址賦給這幾個數(shù)組中下標 70(主設(shè)備號所對應(yīng)的指針元素即可。這一過程是在后面的加載函數(shù)中完成的。static int blksize = blkdemo_blksize;struct blkdemo_device blkdemo_devblkdemo_devs;/這里才真正創(chuàng)建了我們虛擬塊設(shè)備對應(yīng)的結(jié)構(gòu)體變量 (一個全局數(shù)組 , /每個元素為對應(yīng)一個虛擬塊設(shè)備虛擬塊設(shè)備的打開函數(shù) (open(:int blkdemo_open(struct i

7、node *inode, strcut file *filp /設(shè)備文件對應(yīng)的節(jié)點 (inode結(jié)構(gòu)中包含有對應(yīng)的設(shè)備號intnum;num = DEVICE_NR(inode->i_rdev;/用 DEVICE_NR宏可求出該節(jié)點所對應(yīng)設(shè)備的次設(shè)備號,所以 num 即為次設(shè)備號 if (!blkdemo_devnum.use_cnt /如果該設(shè)備的使用計數(shù)為 0,則說該設(shè)備沒有被任何程序使用,當(dāng)虛擬塊設(shè)備沒有被 /任何程序使用時,內(nèi)核先前為該設(shè)備所分配的存儲區(qū)很可能已經(jīng)被釋放掉了,甚至對于可移動設(shè)備而言,有可能該設(shè)備都被拔掉了(當(dāng) /然,我們的虛擬塊設(shè)備是不可能的 ,因此,在打開該設(shè)備

8、時要進行嚴格的檢查,不然會導(dǎo)致設(shè)備打開出錯而造成系統(tǒng)崩潰。check_disk_change(inode->i_rdev;/首先檢查該塊設(shè)備是否發(fā)生了變化,比如已經(jīng)被移除了(該設(shè)備不可能,所以 /此處沒有用 if 來判斷,只是形式的調(diào)用了一下該函數(shù)。if(!blkdemo_devnum.data/然后判斷該設(shè)備的數(shù)據(jù)存儲區(qū)域是否已經(jīng)被釋放掉了returnENOMEM;/如果是,則返回,告知系統(tǒng)該設(shè)備無法打開, -ENOMEM 是一個內(nèi)核中定義的宏,它代表的意思是 /“ error,no memory” 。/如果上述情況均未發(fā)生,一切正常,則打開設(shè)備,對于這個虛擬的塊設(shè)備,其實沒有什么好打

9、開的,不過還是意思一下:blkdemo_devnum.use_cnt+;/將設(shè)備的使用計數(shù)加 1,表示又多了個程序使用該設(shè)備。MOD_INC_USE_COUNT;/并且將內(nèi)核所管理的模塊使用計數(shù)也加 1, 好讓內(nèi)核也知道多了一個程序使用該虛擬設(shè)備模塊。 模塊使 /用計數(shù)是內(nèi)核管理模塊時要用的,只有當(dāng)一個設(shè)備的模塊使用計數(shù)為 0時才能卸載該模塊,這個值也可以通過 lsmod 命令查看到 return(0;/返回 0,表示設(shè)備已成功打開虛擬塊設(shè)備的釋放函數(shù) (release(:int blkdemo_release(struct inode *inode, struct file *filp/釋放

10、并不代表將此設(shè)備從內(nèi)核中移除了,他是對調(diào)用它的程序而言的,只表示這個程序不再使用該設(shè)備了intnum;num = DEVICE_NR(inode->i_rdev;/求出設(shè)備的次設(shè)備號blkdemo_devnum.use_cnt-;/既然使用該設(shè)備的程序少了一個,則應(yīng)該將該設(shè)備的使用計數(shù)減 1MOD_DEC_USE_COUNT;/ 并且將內(nèi)核所管理的模塊使用計數(shù)也減 1return(0;/返回 0,表示設(shè)備釋放成功虛擬塊設(shè)備的請求函數(shù) (request(:void blkdemo_request(request_queue_t *q /塊設(shè)備和字符設(shè)備在數(shù)據(jù)的讀寫是有區(qū)別的。對于塊設(shè)備,程

11、序?qū)?shù)據(jù)讀寫的請求一般不會立即得到回應(yīng),程序首先要提出對數(shù)據(jù) /的請求,此時內(nèi)核會動態(tài)的分配一個 request 結(jié)構(gòu)(page74,圖 7-1中有 request 結(jié)構(gòu)的抽象描述 ,并將請求的詳細信息記錄到 /這個 request 結(jié)構(gòu)中,然后將這個結(jié)構(gòu)按照某些規(guī)則插入到該設(shè)備的請求隊列中,當(dāng)系統(tǒng)處于較為合適的狀態(tài)時,內(nèi)核就會對隊列上 /的所有請求進行集中處理。 采用這些繁瑣的方法都由真實塊設(shè)備的物理特性決定的,因為大部分塊設(shè)備都和硬盤類似, 讀取數(shù)據(jù)時要進 /行尋道等一些復(fù)雜的命令操作, 而這是一個相當(dāng)耗時的過程, 如果每當(dāng)有程序請求數(shù)據(jù)時內(nèi)核就立即去操作磁盤, 那么系統(tǒng)大部分寶貴 /的時

12、間都被消耗在了等待磁盤響應(yīng)上了, 因此內(nèi)核中構(gòu)建了一套專門操作塊設(shè)備的方法, 來對請求的數(shù)據(jù)進行集中處理, 以提高磁盤的 /吞吐量和系統(tǒng)的整體性能, request(函數(shù)的任務(wù)就是按順序處理這條請求隊列,直到隊尾, /除非出現(xiàn)意外錯誤而返回。struct request *req;int res = 1; /用來記錄對當(dāng)前請求的處理是否成功,成功則置 1,失敗則清 0,供后面的 end_request(函數(shù)使用。intnum;intsize;u8*ptr;while (1 INIT_REQUEST;/測試當(dāng)前的請求是否有效req=CURRENT; /CURRENT指針由內(nèi)核中的 end_req

13、uest(函數(shù)管理,它指向請求隊列中當(dāng)前要處理的 request 結(jié)構(gòu)。 num=DEVICE_NR(req->rq_dev;/獲取所請求的設(shè)備的次設(shè)備號ptr = blkdemo_devnum.data + req->sector * blkdemo_devnum.hardsect;/ 設(shè)備數(shù)據(jù)存儲區(qū)的首地址 + 請求的首個扇區(qū) * 該設(shè)備每個扇區(qū)的字節(jié)大小,最后, ptr 指向所要請求的數(shù)據(jù) size = req->current_nr_sectors * blkdemo_devnum.hardsect;/ 當(dāng)前請求的扇區(qū)總數(shù) * 該設(shè)備每個扇區(qū)的字節(jié)大小,因此 size

14、 為當(dāng)前請求所請求的總字節(jié)數(shù)if (ptr + size > blkdemo_devnum.data + blkdemo_devnum.size /判斷所請求數(shù)據(jù)的地址是否超出 /了該設(shè)備的數(shù)據(jù)存儲區(qū)的范圍。超出范圍后會導(dǎo)致內(nèi)存溢出,造成系統(tǒng)崩潰,決不能容忍。printk(KERN_WARNNING “blkdemo: request past end of devicen”; /向控制臺或日志打印出警告信息 res=0;/請求失敗, res 置 0/如果正常則下面打印出當(dāng)前請求的詳細信息(僅調(diào)試時使用,可以不寫printk(“<1> request %p: cmd %i s

15、ec %li (nr.%lin”, req,/<1>和 KERN_ALERT是等價的,這是內(nèi)核中定 req->cmd, req->sector, req->current_nr_sectors;/義的 8種日志級別宏之一(page43switch(cmd /判斷當(dāng)前請求要對所請求的數(shù)據(jù)做何種操作caseREAD:/如果是讀,則,memcpy(req->buffer,ptr,size; /把從 ptr 開始的 size 字節(jié)復(fù)制到發(fā)出該請求的程序所提供的緩沖區(qū)中去 res=1; /完成了請求, res 置 1break;caseWRITE:/如果是寫,則,me

16、mcpy(ptr,req->buffer,size; /把發(fā)出該請求的程序的緩沖區(qū)中的數(shù)據(jù)復(fù)制到該設(shè)備中 ptr 所指向的內(nèi)存區(qū) res=1;/完成了請求, res 置 1break;default: /未知請求res=0; /無法完成, res 置 0end_request(res;/根據(jù)請求是否成功來調(diào)整 CURRENT 指針變量的值,為處理請求隊列中的下一個請求作準備struct block_device_operations blkdemo_bdops = /初始化虛擬塊設(shè)備操作函數(shù)接口open: blkdemo_open,release: blkdemo_release,;虛擬

17、塊設(shè)備的加載函數(shù):static int _init blkdemo_init(void/_init為加載函數(shù)標志,用此標志修飾的函數(shù)只能在模塊被插入內(nèi)核由內(nèi)核調(diào)用 inti;intret;ret = devfs_register_blkdev(MAJOR_NR, DEVICE_NAME, &blkdemo_bdops;/注冊塊設(shè)備,該函數(shù)成功時返回主設(shè) /備號,失敗時返回負值,當(dāng)參數(shù)中主設(shè)備號 MAJOR_NR為 0時,自動為設(shè)備分配主設(shè)備號,非 0時使用 MAJOR_NR指定的主設(shè)備號 if (ret < 0 /如果返回值小于 0,說明設(shè)備注冊失敗printk(KERN_WAR

18、NNING “devfs_register_blkdev( failedn”; /打印出警告信息return(ret;/返回錯誤代號if (MAJOR_NR = 0/如果 MAJOR_NR為 0,則blkdemo_major=ret;/使用系統(tǒng)自動分配的主設(shè)備號else/否則blkdemo_major=MAJOR_NR;/直接使用我們指定的主設(shè)備號blk_init_queue(BLK_DEFAULT_QUEUE(blkdemo_major,blkdemo_request;/內(nèi)核為每個主設(shè)備號都保留了一個請求 /隊列, 也是通過一個數(shù)組實現(xiàn)的, BLK_DEFAULT_QUEUE能返回該默認的請

19、求隊列, blk_init_queue(函數(shù)通過創(chuàng)建一個請求隊列 /頭將該隊列和處理該請求隊列的 request(關(guān)聯(lián)起來/ 下面的就開始將我們所創(chuàng)造的虛擬塊設(shè)備的信息告訴系統(tǒng):read_aheadblkdemo_major = blkdemo_rahead; /告訴系統(tǒng)該類型塊設(shè)備的預(yù)讀扇區(qū)數(shù)for (i = 0; i < blkdemo_devs; i+blkdemo_sizesi=blkdemo_size;/確定每個塊設(shè)備的大小,以 KB 為單位blk_sizeblkdemo_major = blkdemo_sizes;/告訴系統(tǒng)保存有這些塊設(shè)備的大小的數(shù)組的內(nèi)存首地址for (i

20、 = 0; i < blkdemo_devs; i+blkdemo_blksizesi=blkdemo_blksize;/確定每個塊設(shè)備的每個數(shù)據(jù)塊的大小,以字節(jié)為單位blksize_sizeblkdemo_major = blkdemo_blksizes;/告訴系統(tǒng)保存有這些塊設(shè)備的每個數(shù)據(jù)塊大小的數(shù)組的首地址 for (i = 0; i < blkdemo_devs; i+blkdemo_hardsectsi=blkdemo_hardsect;/確定每個塊設(shè)備的每個扇區(qū)的大小,以字節(jié)為單位hardsect_sizeblkdemo_major = blkdemo_hardsect

21、s;/告訴系統(tǒng)保存有這些塊設(shè)備的每個扇區(qū)大小的數(shù)組的首地址for (i = 0; i < blkdemo_devs; i+register_disk(NULL, MKDEV(blkdemo_major, i, 1, &blkdemo_bdops,/注冊每個塊設(shè)備分區(qū)。由于我們的虛 blkdemo_size<<1; /擬塊設(shè)備沒有實行分區(qū),相當(dāng)于只有一個分區(qū),也就沒用到 gendisk 分區(qū)結(jié)構(gòu), /因此第一個參數(shù)為 NULL ,表示不做任何分區(qū)操作。 MKDEV(宏能夠?qū)⒅髟O(shè)備號和次設(shè)備號組合成一個完整的設(shè)備號,最后一個參數(shù)要 /將 blkdemo_size左移 1位

22、是因為 blkdemo_size的單位為 KB ,而 register_disk要求的單位是扇區(qū),該塊設(shè)備的一個扇區(qū)為 /512字節(jié),所以要將 blkdemo_size乘以 2才是扇區(qū)數(shù),即左移兩位。for (i = 0; i < blkdemo_devs; i+ /初始化前面所創(chuàng)建的虛擬塊設(shè)備的結(jié)構(gòu)體變量blkdemo_devi.size = 1024 * blkdemo_size;/確定該塊設(shè)備的大小,單位為字節(jié)blkdemo_devi.hardsect=blkdemo_hardsectsi;/確定該塊設(shè)備每個扇區(qū)的字節(jié)數(shù),/ 由于 blkdemo_hardsects數(shù)組保存的也是這個值,并且已經(jīng)在前面初始化,因此可直接賦給該結(jié)構(gòu)中的 hardsectblkdemo_devi.data = kmalloc(blkdemo_size * blkdemo_blksize * sizeof(char, GFP_KERNEL; / 根據(jù)上面的大小為該虛擬設(shè)備分配數(shù)據(jù)存儲區(qū),上面 kmalloc(函數(shù)參數(shù)中的“ *”號都是乘號,不是指針。 GFP_KERNEL是內(nèi)核分 /配內(nèi)存頁的一種方式,以這種方式分配內(nèi)存時成功的幾率最大,但也可能失敗,失敗時返回

溫馨提示

  • 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)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論