




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動第 13 章Linux 塊設(shè)備驅(qū)動塊設(shè)備是與字符設(shè)備并列的概念,這兩類設(shè)備在 Linux 中驅(qū)動的結(jié)構(gòu)有較大差異, 總體而言,塊設(shè)備驅(qū)動比字符設(shè)備驅(qū)動要復(fù)雜得多,在 I/O 操作上表現(xiàn)出極大的不同, 緩沖、I/O 調(diào)度、請求隊(duì)列等都是與塊設(shè)備驅(qū)動相關(guān)的概念。本章將詳細(xì)講解 Linux 塊設(shè)備驅(qū)動的編程方法。13.1 節(jié)講解塊設(shè)備 I/O 操作的特點(diǎn),分析字符設(shè)備與塊設(shè)備在 I/O 操作上的差異。13.2 節(jié)從整體上描述 Linux 塊設(shè)備驅(qū)動的結(jié)構(gòu),分析主要的數(shù)據(jù)結(jié)構(gòu)、函數(shù)及其關(guān)系。13.313.5 節(jié)分別講解塊設(shè)備驅(qū)動模塊加載與
2、卸載、打開與和 ioctl()函數(shù)。13.6 節(jié)非常重要,講述了塊設(shè)備 I/O 操作所依賴的請求隊(duì)列的概念及用法。13.2 節(jié)與 13.313.6 節(jié)是整體與部分的關(guān)系,13.213.6 節(jié)與 13.7 節(jié)是迭代遞進(jìn)的關(guān)系。13.7 節(jié)在 13.113.6 節(jié)講解內(nèi)容的基礎(chǔ)上,總結(jié) Linux 下塊設(shè)備的讀寫流程,而13.7 節(jié)則講解了塊設(shè)備驅(qū)動的具體實(shí)例,即 RamDisk 的驅(qū)動。學(xué)院華清遠(yuǎn)見旗下品牌:Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動字符設(shè)備與塊設(shè)備 I/O 操作的不同如下。(1)塊設(shè)備只能以塊為接受輸入和返回輸出,而字符設(shè)備則以字節(jié)為。大多數(shù)設(shè)備是字符設(shè)備
3、,因?yàn)樗鼈儾恍枰彌_而且不以固定塊大小進(jìn)行操作。(2)塊設(shè)備對于 I/O 請求有對應(yīng)的緩沖區(qū),因此它們可以選擇以什么順序進(jìn)行響應(yīng),字符設(shè)備無須緩沖且被直接讀寫。對于因?yàn)樵谧x寫連續(xù)的扇區(qū)比分離的扇區(qū)更快。設(shè)備而言調(diào)整讀寫的順序作用巨大,(3)字符設(shè)備只能被順序讀寫,而塊設(shè)備可以隨機(jī)但是對于磁盤這類機(jī)械設(shè)備而言,順序地組織塊設(shè)備的。雖然塊設(shè)備可隨機(jī),可以提高性能,如圖 13.1所示,對扇區(qū) 1、10、3、2 的請求被調(diào)整為對扇區(qū) 1、2、3、10 的請求。而對 SD 卡、RamDisk 等塊設(shè)備而言,不機(jī)械上的,進(jìn)行這樣的調(diào)整沒有必要。圖 13.1 調(diào)整塊設(shè)備 I/O 操作的順序13.2.1blo
4、ck_device_operations 結(jié)構(gòu)體在塊設(shè)備驅(qū)動中,有 1 個(gè)類似于字符設(shè)備驅(qū)動中 file_operations 結(jié)構(gòu)體的block_device_operations 結(jié)構(gòu)體,它是對塊設(shè)備操作的集合,定義如代碼13.1 所示。代碼13.1 block_device_operations 結(jié)構(gòu)體學(xué)院華清遠(yuǎn)見旗下品牌:1 struct block_device_operations 2 3int(*open)(struct inode *, struct file*); /打開Linux 塊設(shè)備驅(qū)動結(jié)構(gòu)塊設(shè)備的 I/O 操作特點(diǎn)Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux
5、塊設(shè)備驅(qū)動下面對其主要的成員函數(shù)進(jìn)行分析。1打開和與字符設(shè)備驅(qū)動類似,當(dāng)設(shè)備被打開和關(guān)閉時(shí)將調(diào)用它們。2IO上述函數(shù)是 ioctl()系統(tǒng)調(diào)用的實(shí)現(xiàn),塊設(shè)備包含大量的標(biāo)準(zhǔn)請求,這些標(biāo)準(zhǔn)請求由 Linux 塊設(shè)備層處理,因此大部分塊設(shè)備驅(qū)動的 ioctl()函數(shù)相當(dāng)短。3介質(zhì)改變被內(nèi)核調(diào)用來檢查是否驅(qū)動器中的介質(zhì)已經(jīng)改變,如果是,則返回一個(gè)非 0 值, 否則返回 0。這個(gè)函數(shù)僅適用于支持可移動介質(zhì)的驅(qū)動器,通常需要在驅(qū)動中增加一個(gè)表示介質(zhì)狀態(tài)是否改變的標(biāo)志變量,非可移動設(shè)備的驅(qū)動不需要實(shí)現(xiàn)這個(gè)方法。4使介質(zhì)有效revalidate_disk()函數(shù)被調(diào)用來響應(yīng)一個(gè)介質(zhì)改變,它給驅(qū)動一個(gè)機(jī)會來進(jìn)行
6、必要的工作以使新介質(zhì)準(zhǔn)備好。5獲得驅(qū)動器信息該函數(shù)根據(jù)驅(qū)動器的幾何信息填充一個(gè) hd_geometry 結(jié)構(gòu)體,hd_geometry 結(jié)構(gòu)體學(xué)院華清遠(yuǎn)見旗下品牌:int (*getgeo)(struct block_device *, struct hd_geometry *);int (*revalidate_disk) (struct gendisk *gd);int (*media_changed) (struct gendisk *gd);int (*ioctl)(struct inode *inode, struct file *filp, unsigned int cmd,uns
7、igned long arg);int (*open)(struct inode *inode, struct file *filp);int (*release)(struct inode *inode, struct file *filp);4 int(*release)(struct inode *, struct file*); /5 int(*ioctl)(struct inode *, struct file *, unsigned, unsigned long);/ioctl6 long(*unlocked_ioctl)(struct file *, unsigned, unsi
8、gned long);7 long(*compat_ioctl)(struct file *, unsigned, unsigned long);8 int(*direct_access)(struct block_device *, sector_t, unsigned long*);9 int(*media_changed)(struct gendisk*); /介質(zhì)被改變?10 int(*revalidate_disk)(struct gendisk*); /使介質(zhì)有效11 int(*getgeo)(struct block_device *, struct hd_geometry*);
9、/填充驅(qū)動器信息12 struct module *owner; /模塊擁有者13 ;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動包含磁頭、扇區(qū)、柱面等信息。6模塊指針一個(gè)指向擁有這個(gè)結(jié)構(gòu)體的模塊的指針,它通常被初始化為 THIS_MODULE。13.2.2gendisk 結(jié)構(gòu)體在 Linux 內(nèi)核中,使用 gendisk(通用磁盤)結(jié)構(gòu)體來表示 1 個(gè)分區(qū)),這個(gè)結(jié)構(gòu)體的定義如代碼13.2 所示。的磁盤設(shè)備(或代碼13.2gendisk 結(jié)構(gòu)體major、first_minor 和 minors 共同表征了磁盤的主、次設(shè)備號,同一個(gè)磁盤的各個(gè)分區(qū)共享一個(gè)主設(shè)備號,而次設(shè)備
10、號則不同。fops 為 block_device_operations,即上節(jié)描述的塊設(shè)備操作集合。queue 是內(nèi)核用來管理這個(gè)設(shè)備的 I/O 請求隊(duì)列的指針。capacity 表明設(shè)備的容量,以 512 個(gè)字節(jié)為。private_data 可用于指向磁盤的任何私有數(shù)據(jù),用法與字符設(shè)備驅(qū)動 file 結(jié)構(gòu)體的 private_data 類似。Linux 內(nèi)核提供了一組函數(shù)來操作 gendisk,如下所示。學(xué)院華清遠(yuǎn)見旗下品牌:1 struct gendisk 2 3 int major; /* 主設(shè)備號 */4 int first_minor; /*第 1 個(gè)次設(shè)備號*/5 int mino
11、rs; /* 最大的次設(shè)備數(shù),如果不能分區(qū),則為 1*/6 char disk_name32; /* 設(shè)備名稱 */7 struct hd_struct *part; /* 磁盤上的分區(qū)信息 */8 struct block_device_operations *fops; /*塊設(shè)備操作結(jié)構(gòu)體*/9 struct request_queue *queue; /*請求隊(duì)列*/10 void *private_data; /*私有數(shù)據(jù)*/11 sector_t capacity; /*扇區(qū)數(shù),512 字節(jié)為 1 個(gè)扇區(qū)*/ 1213 int flags;14 char devfs_name64;
12、15 int number;16 struct device *driverfs_dev;17 struct kobject kobj; 1819 struct timer_rand_state *random;20 int policy; 2122 atomic_t sync_io; /* RAID */23 unsigned long stamp;24 int in_flight;25 #ifdef CONFIG_SMP26 struct disk_stats *dkstats;27 #else28 struct disk_stats dkstats;29 #endif 30 ;struc
13、t module *owner;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動1分配 gendiskgendisk 結(jié)構(gòu)體是一個(gè)動態(tài)分配的結(jié)構(gòu)體,它需要特別的內(nèi)核操作來初始化,驅(qū)動不能分配這個(gè)結(jié)構(gòu)體,而應(yīng)該使用下列函數(shù)來分配 gendisk:minors 參數(shù)是這個(gè)磁盤使用的次設(shè)備號的數(shù)量,一般也就是磁盤分區(qū)的數(shù)量,此后 minors 不能被修改。2增加 gendiskgendisk 結(jié)構(gòu)體被分配之后,系統(tǒng)還不能使用這個(gè)磁盤,需要調(diào)用如下函數(shù)來個(gè)磁盤設(shè)備。這特別要注意的是對 add_disk()的調(diào)用必須發(fā)生在驅(qū)動程序的初始化工作完成并能響應(yīng)磁盤的請求之后。3gendisk當(dāng)
14、不再需要一個(gè)磁盤時(shí),應(yīng)當(dāng)使用如下函數(shù)gendisk。4gendisk計(jì)數(shù)gendisk 中包含一個(gè) kobject 成員,因此,它是一個(gè)可被計(jì)數(shù)的結(jié)構(gòu)體。通過get_disk()和 put_disk()函數(shù)可用來操作計(jì)數(shù),這個(gè)工作一般不需要驅(qū)動親自做。通常對 del_gendisk()的調(diào)用會去掉 gendisk 的最終計(jì)數(shù),但是這一點(diǎn)并不是必須的。因此,在 del_gendisk()被調(diào)用后,這個(gè)結(jié)構(gòu)體可能繼續(xù)。5設(shè)置 gendisk 容量塊設(shè)備中最小的可尋址單元是扇區(qū),扇區(qū)大小一般是 2 的整數(shù)倍,最常見的大小是 512 字節(jié)。扇區(qū)的大小是設(shè)備的物理屬性,扇區(qū)是所有塊設(shè)備的基本單元,塊設(shè)備
15、無法對比它還小的單元進(jìn)行尋址和操作,不過許多塊設(shè)備能夠一次就傳輸多個(gè)扇區(qū)。雖然大多數(shù)塊設(shè)備的扇區(qū)大小都是 512 字節(jié),不過其他大小的扇區(qū)也很常見,比如, 很多 CD-ROM 盤的扇區(qū)都是 2KB。不管物理設(shè)備的真實(shí)扇區(qū)大小是多少,內(nèi)核與塊設(shè)備驅(qū)動交互的扇區(qū)512 字節(jié)為。因此,set_capacity()函數(shù)也以 512 字節(jié)為。13.2.3request 與bio 結(jié)構(gòu)體1請求在 Linux 塊設(shè)備驅(qū)動中,使用 request 結(jié)構(gòu)體來表征等待進(jìn)行的 I/O 請求,這個(gè)結(jié)構(gòu)體的定義如代碼13.3 所示。代碼13.3 request 結(jié)構(gòu)體學(xué)院華清遠(yuǎn)見旗下品牌:void set_capaci
16、ty(struct gendisk *disk, sector_t size);void del_gendisk(struct gendisk *gd);void add_disk(struct gendisk *gd);struct gendisk *alloc_disk(int minors);Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動request 結(jié)構(gòu)體的主要成員包括:上述 3 個(gè)成員標(biāo)識還未完成的扇區(qū),hard_sector 是第一個(gè)尚未傳輸?shù)纳葏^(qū),hard_nr_sectors 是尚待完成的扇區(qū)數(shù),hard_cur_sectors 是當(dāng)前 I/O 操作中待完成
17、的扇區(qū)數(shù)。這些成員只用于內(nèi)核塊設(shè)備層,驅(qū)動不應(yīng)當(dāng)使用它們,如下所示:學(xué)院華清遠(yuǎn)見旗下品牌:sector_t sector;unsigned long nr_sectors;sector_t hard_sector; unsigned long hard_nr_sectors;unsigned int hard_cur_sectors;1 struct request 2 3 struct list_head queuelist; /*鏈表結(jié)構(gòu)*/4 unsigned long flags; /* REQ_ */ 56 sector_t sector; /* 要傳送輸?shù)南乱粋€(gè)扇區(qū) */7 uns
18、igned long nr_sectors; /*要傳送的扇區(qū)數(shù)目*/8 /*當(dāng)前要傳送的扇區(qū)數(shù)目*/9 unsigned int current_nr_sectors; 1011 sector_t hard_sector; /*要完成的下一個(gè)扇區(qū)*/12 unsigned long hard_nr_sectors; /*要被完成的扇區(qū)數(shù)目*/13 /*當(dāng)前要被完成的扇區(qū)數(shù)目*/14 unsigned int hard_cur_sectors; 1516 struct bio *bio; /*請求的 bio 結(jié)構(gòu)體的鏈表*/17 struct bio *biotail; /*請求的 bio 結(jié)
19、構(gòu)體的鏈表尾*/ 1819 void *elevator_private;2021 unsigned short ioprio; 2223 int rq_status;24 struct gendisk *rq_disk;25 int errors;26 unsigned long start_time; 2728 /*請求在物理內(nèi)存中占據(jù)的不連續(xù)的段的數(shù)目,scatter/gather 列表的*/29 unsigned short nr_phys_segments; 3031 /*與 nr_phys_segments 相同,但考慮了系統(tǒng) I/O MMU 的remap */32 unsigne
20、d short nr_hw_segments; 3334 int tag;35 char *buffer; /*傳送的緩沖,內(nèi)核虛擬地址*/ 3637 int ref_count; /*計(jì)數(shù) */ 38 .39 ;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動驅(qū)動中會經(jīng)常與這 3 個(gè)成員打交道,這 3 個(gè)成員在內(nèi)核和驅(qū)動交互中發(fā)揮著作用。它們以 512 字節(jié)大小為一個(gè)扇區(qū),如果硬件的扇區(qū)大小不是 512 字節(jié),則需要進(jìn)行相應(yīng)的調(diào)整。例如,如果硬件的扇區(qū)大小是 2048 字節(jié),則在進(jìn)行硬件操作之前,需要用 4 來除起始扇區(qū)號。hard_sector 、 hard_nr_sect
21、ors 、 hard_cur_sectors與 sector 、 nr_sectors 、current_nr_sectors 之間可認(rèn)為是“副本”關(guān)系。bio 是這個(gè)請求中包含的 bio 結(jié)構(gòu)體的鏈表,驅(qū)動中不宜直接存取這個(gè)成員,而應(yīng)該使用后文將的rq_for_each_bio()。指向緩沖區(qū)的指針,數(shù)據(jù)應(yīng)當(dāng)被傳送到或者來自這個(gè)緩沖區(qū),這個(gè)指針是一個(gè)內(nèi)核虛擬地址,可被驅(qū)動直接。該值表示相鄰的頁被合并后,這個(gè)請求在物理內(nèi)存中占據(jù)的段的數(shù)目。如備支持分散/( SG , scatter/gather ) 操作, 可依據(jù)此字段申請sizeof(scatterlist)* nr_phys_segmen
22、ts 的內(nèi)存,并使用下列函數(shù)進(jìn)行 DMA:該函數(shù)與 dma_map_sg()類似,它返回 scatterlist 列表的數(shù)量。用于這個(gè)請求到請求隊(duì)列的鏈表結(jié)構(gòu),blkdev_dequeue_request()可用于從隊(duì)列中移除請求。使用如以從request 獲得數(shù)據(jù)傳送的方向。0 返回值表示從設(shè)備中讀,非 0 返回值表示向設(shè)備寫。2請求隊(duì)列一個(gè)塊請求隊(duì)列是一個(gè)塊 I/O 請求的隊(duì)列,其定義如代碼代碼13.4 request 隊(duì)列結(jié)構(gòu)體13.4。學(xué)院華清遠(yuǎn)見旗下品牌:1 struct request_queue 2 3.4 /* 保護(hù)隊(duì)列結(jié)構(gòu)體的自旋鎖 */5 spinlock_t _ _que
23、ue_lock;6 spinlock_t *queue_lock; 78 /* 隊(duì)列 kobject */9 struct kobject kobj;10rq_data_dir(struct request *req);struct list_head queuelist;int blk_rq_map_sg(request_queue_t) *q, struct request *req,struct scatterlist *sglist;unsigned short nr_phys_segments;char *buffer;struct bio *bio;unsigned int cur
24、rent_nr_sectors;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動請求隊(duì)列跟蹤等候的塊 I/O 請求,它用于描述這個(gè)設(shè)備能夠支持的請求的類型信息、它們的最大大小、多少不同的進(jìn)入一個(gè)請求、硬件扇區(qū)大小、對齊要求等參數(shù),其結(jié)果是:如果請求隊(duì)列被配置正確了,它請求。交給該設(shè)備一個(gè)不能處理的請求隊(duì)列還實(shí)現(xiàn)一個(gè)接口,這個(gè)接口使用多個(gè) I/O 調(diào)度器,I/O 調(diào)度器(也稱電梯)的工作是以最優(yōu)性能的方式向驅(qū)動提交 I/O 請求。大部分 I/O 調(diào)度器累積批量的 I/O 請求,并將它們排列為遞增(或遞減)的塊索引順序后提交給驅(qū)動。進(jìn)行這些工作的在于,對于磁頭而言,當(dāng)給定順序排列的
25、請求時(shí),可以使得磁盤順序地從一頭到另一頭工作,非常像一個(gè)滿載的電梯,在一個(gè)方向移動直到所有它的“請求”被滿足。學(xué)院華清遠(yuǎn)見旗下品牌:11 /* 隊(duì)列設(shè)置 */12 unsigned long nr_requests; /* 最大的請求數(shù)量 */13 unsigned int nr_congestion_on;14 unsigned int nr_congestion_off;15 unsigned int nr_batching; 1617 unsigned short max_sectors; /* 最大的扇區(qū)數(shù) */18 unsigned short max_hw_sectors;19 u
26、nsigned short max_phys_segments; /* 最大的*/20 unsigned short max_hw_segments;21 unsigned short hardsect_size; /* 硬件扇區(qū)*/22 unsigned int max_segment_size; /* 最大的段*/ 2324 unsigned long seg_boundary_mask; /* 段邊界掩碼 */25 unsigned int dma_alignment; /* DMA 傳送的內(nèi)存對齊限制 */ 2627 struct blk_queue_tag *queue_tags;
27、2829 atomic_t refcnt; /*計(jì)數(shù) */3031 unsigned int in_flight; 3233 unsigned int sg_timeout;34 unsigned int sg_size;35 int node; 3637 struct list_head drain_list;3839 struct request *flush_rq;40 unsigned char ordered; 41 ;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動另外,I/O 調(diào)度器還負(fù)責(zé)合并鄰近的請求,當(dāng)一個(gè)新 I/O 請求被提交給調(diào)度器后,它會在隊(duì)列里搜尋包含
28、鄰近扇區(qū)的請求。如果找到一個(gè),并且如果結(jié)果的請求不是太大, 調(diào)度器將合并這兩個(gè)請求。對磁盤等塊設(shè)備進(jìn)行 I/O 操作順序的調(diào)度類似于電梯的原理,先服務(wù)完上樓的乘客,再服務(wù)下樓的乘客效率會更高,而順序響應(yīng)用戶的請求則電梯會無序地忙亂。Linux 2.6 內(nèi)核包含 4 個(gè) I/O 調(diào)度器,它們分別是 No-op I/O scheduler、Anticipatory I/O scheduler、Deadline I/O scheduler 與 CFQ I/O scheduler。Noop I/O scheduler 是一個(gè)簡化的調(diào)度程序,它只作最基本的合并與排序。Anticipatory I/O s
29、cheduler 是當(dāng)前內(nèi)核中默認(rèn)的 I/O 調(diào)度器,它擁有非常好的性能, 在Linux 2.5 內(nèi)核中它就相當(dāng)引人注意。在與Linux 2.4 內(nèi)核進(jìn)行的對比測試中,在Linux2.4 內(nèi)核中多項(xiàng)以分鐘為完成的任務(wù),它則是以秒為來完成的,正因?yàn)槿绱怂蔀槟壳?Linux 2.6 內(nèi)核中默認(rèn)的 I/O 調(diào)度器。Anticipatory I/O scheduler 的缺點(diǎn)是比較龐大與復(fù)雜,在一些特殊的情況下,特別是在數(shù)據(jù)吞吐量非常大的數(shù)據(jù)庫系統(tǒng)中它會變得比較緩慢。Deadline I/O scheduler 是Anticipatory I/O scheduler 的缺點(diǎn)進(jìn)行而來的,表現(xiàn)出的性能幾
30、乎與 Anticipatory I/O scheduler 一樣好,但是比 Anticipatory 小巧。CFQ I/O scheduler 為系統(tǒng)內(nèi)的所有任務(wù)分配相同的帶寬,提供一個(gè)公平的工作環(huán)境,它比較適合桌面環(huán)境。事實(shí)上在測試中它也有不錯(cuò)的表現(xiàn),mplayer、xmms 等多器與它配合的相當(dāng)好,回放平滑,幾乎沒有因磁盤而出現(xiàn)的跳幀現(xiàn)象。內(nèi)核block 目錄中的 noop-iosched.c、as-iosched.c、deadline-iosched.c 和cfq-iosched.c文件分別實(shí)現(xiàn)了上述調(diào)度算法??梢酝ㄟ^給 kernel 添加啟動參數(shù),選擇使用的 IO 調(diào)度算法,如:(1)
31、初始化請求隊(duì)列。該函數(shù)的第一個(gè)參數(shù)是請求處理函數(shù)的指針,第二個(gè)參數(shù)是隊(duì)列權(quán)限的自旋鎖,這個(gè)函數(shù)會發(fā)生內(nèi)存分配的行為,它可能會失敗,因此一定要檢查它的返回值。這個(gè)函數(shù)一般在塊設(shè)備驅(qū)動的模塊加載函數(shù)中調(diào)用。(2)清除請求隊(duì)列。這個(gè)函數(shù)完成將請求隊(duì)列返回給系統(tǒng)的任務(wù),一般在塊設(shè)備驅(qū)動模塊卸載函數(shù)中調(diào)用。而 blk_put_queue()宏則定義為:(3)分配“請求隊(duì)列”。對于 Flash、RAM 盤等完全隨機(jī)的非機(jī)械設(shè)備,并不需要進(jìn)行復(fù)雜的 I/O 調(diào)度,這個(gè)時(shí)候,應(yīng)該使用上述函數(shù)分配一個(gè)“請求隊(duì)列”,并使用如下函數(shù)來綁定請求隊(duì)列和“請求”函數(shù)。學(xué)院華清遠(yuǎn)見旗下品牌:void blk_queue_m
32、ake_request(request_queue_t * q, make_request_fn * mfn);request_queue_t *blk_alloc_queue(int gfp_mask);#define blk_put_queue(q) blk_cleanup_queue(q)void blk_cleanup_queue(request_queue_t * q);request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t*lock);kernel elevator=deadlineLinux 設(shè)備驅(qū)動開發(fā)詳
33、解第 13 章、Linux 塊設(shè)備驅(qū)動在 13.6.2 節(jié)我們會看到,這種方式分配的“請求隊(duì)列”實(shí)際上不包含任何請求,所以給其加上引號。(4)提取請求。上述函數(shù)用于返回下一個(gè)要處理的請求(由 I/O 調(diào)度器決定),如果沒有請求則返回 NULL。elv_next_request()標(biāo)識它為活動的,這個(gè)標(biāo)識將清除請求,它仍然將這個(gè)請求保留在隊(duì)列上,但是I/O 調(diào)度器合并其他的請求到已開始執(zhí)行的請求。因?yàn)?elv_next_request() 不從隊(duì)列里清除請求,因此連續(xù)調(diào)用它兩次,兩次會返回同一個(gè)請求結(jié)構(gòu)體。(5)去除請求。上述函數(shù)從隊(duì)列中去除一個(gè)請求。如果驅(qū)動中同時(shí)從同一個(gè)隊(duì)列中操作了多個(gè)請求,
34、它必須以這樣的方式將它們從隊(duì)列中去除。如果需要將一個(gè)已經(jīng)出列的請求歸還到隊(duì)列中,可以進(jìn)行以下調(diào)用:另外,塊設(shè)備層還提供了一套函數(shù),這些函數(shù)可被驅(qū)動用來操作,主要包括以下操作。(6)啟停請求隊(duì)列。一個(gè)請求隊(duì)列的如果塊設(shè)備到達(dá)不能處理等候令的狀態(tài),應(yīng)調(diào)用 blk_stop_queue()來告知塊設(shè)備層。之后,請求函數(shù)將不被調(diào)用,除非再次調(diào)用 blk_start_queue()將設(shè)備恢復(fù)到可處理請求的狀態(tài)。(7)參數(shù)設(shè)置。這些函數(shù)用于設(shè)置描述塊設(shè)備可處理的請求的參數(shù)。blk_queue_max_sectors()描述任 請求可包含的最大扇區(qū)數(shù), 默認(rèn)值為 255 ; blk_queue_max_ph
35、ys_segments() 和blk_queue_max_hw_segments()都一個(gè)請求中可包含的最大物理段(系統(tǒng)內(nèi)存中不相鄰的區(qū)),blk_queue_max_hw_segments()考慮了系統(tǒng) I/O 內(nèi)存管理單元的重,這兩個(gè)參數(shù)缺省都是 128。blk_queue_max_segment_size 告知內(nèi)核請求段的最大字節(jié)數(shù),缺省值為 65,536。(8)通告內(nèi)核。該函數(shù)用于告知內(nèi)核塊設(shè)備執(zhí)行 DMA 時(shí)可使用的最高物理地址 dma_addr,如果一個(gè)請求包含超出這個(gè)限制的內(nèi)存,系統(tǒng)將會給這個(gè)操作分配一個(gè)“反彈”緩沖學(xué)院華清遠(yuǎn)見旗下品牌:void blk_queue_bounce
36、_limit(request_queue_t *queue, u64 dma_addr);void blk_queue_max_sectors(request_queue_t *queue, unsigned short max);void blk_queue_max_phys_segments(request_queue_t *queue, unsignedshort max);void blk_queue_max_hw_segments(request_queue_t *queue, unsigned short max);void blk_queue_max_segment_size(r
37、equest_queue_t *queue, unsigned intmax);void blk_stop_queue(request_queue_t *queue); void blk_start_queue(request_queue_t *queue);void elv_requeue_request(request_queue_t *queue, struct request *req);void blkdev_dequeue_request(struct request *req);struct request *elv_next_request(request_queue_t *q
38、ueue);Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動區(qū)。這種方式的代價(jià)昂貴,因此應(yīng)盡量避免使用??梢?給 dma_addr 參 數(shù) 提 供任 何可能 的值 或使 用 預(yù)先 定 義的 宏, 如BLK_BOUNCE_HIGH(對高端內(nèi)存頁使用反彈緩沖區(qū))、BLK_BOUNCE_ISA(驅(qū)動只可在 16MB 的 ISA 區(qū)執(zhí)行 DMA)或者 BLK_BOUCE_ANY(驅(qū)動可在任何地址執(zhí)行 DMA),缺省值是 BLK_BOUNCE_HIGH。如果我們正在驅(qū)動編寫的設(shè)備無法處理一個(gè)特殊大小內(nèi)存邊界的請求,應(yīng)該使用這個(gè)函數(shù)來告知內(nèi)核這個(gè)邊界。例如,如備處理跨 4MB 邊界的請求有
39、,應(yīng)該傳遞一個(gè) 0x3fffff 掩碼,缺省的掩碼是 0xffffffff(對應(yīng) 4GB 邊界)。告知內(nèi)核塊設(shè)備施加于 DMA 傳送的內(nèi)存對齊限制,所有請求都匹配這個(gè)對齊,缺省的是 0x1ff,它導(dǎo)致所有的請求被對齊到 512 字節(jié)邊界。該函數(shù)告知內(nèi)核塊設(shè)備硬件扇區(qū)的大小,內(nèi)核產(chǎn)生的請求都是這個(gè)大小的倍數(shù)并且被正確對界。但是,內(nèi)核塊設(shè)備層和驅(qū)動之間的通信還是以 512 字節(jié)扇區(qū)為進(jìn)行。3塊 I/O通常一個(gè) bio 對應(yīng)一個(gè) I/O 請求,代碼13.5 給出了 bio 結(jié)構(gòu)體的定義。I/O 調(diào)度算法可將連續(xù)的 bio 合并成一個(gè)請求。所以,一個(gè)請求可以包含多個(gè) bio。代碼13.5bio 結(jié)構(gòu)體
40、學(xué)院華清遠(yuǎn)見旗下品牌:1 struct bio 2 3 sector_t bi_sector; /* 要傳輸?shù)牡谝粋€(gè)扇區(qū) */4 struct bio *bi_next; /* 下一個(gè) bio */5 struct block_device*bi_bdev;6 unsigned long bi_flags; /* 狀態(tài)、命令等 */7 unsigned long bi_rw; /* 低位表示 READ/WRITE,表示優(yōu)先級*/89 unsigned short bi_vcnt; /* bio_vec 數(shù)量 */10 unsigned short bi_idx; /* 當(dāng)前 bvl_vec 索
41、引 */ 1112 /*不相鄰的物理段的數(shù)目*/13 unsigned short bi_phys_segments; 1415 /*物理合并和 DMA remap 合并后不相鄰的物理段的數(shù)目*/16 unsigned short bi_hw_segments; 1718 unsigned int bi_size; /* 以字節(jié)為所需傳輸?shù)臄?shù)據(jù)大小 */1920 /* 為了明了最大的 hw,我們考慮這個(gè) bio 中第一個(gè)和最后一個(gè)21 虛擬的可合并的段的*/22 unsigned int bi_hw_front_size;23 unsigned int bi_hw_back_size; 242
42、5 unsigned int bi_max_vecs; /* 我們能持有的最vl_vecs 數(shù) */2627 struct bio_vec *bi_io_vec; /* 實(shí)際的 vec 列表 */28void blk_queue_hardsect_size(request_queue_t *queue, unsigned short max);void blk_queue_dma_alignment(request_queue_t *queue, int mask);blk_queue_segment_boundary(request_queue_t *queue, unsigned long
43、 mask);Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動下面我們對其中的成員進(jìn)行分析:標(biāo)識這個(gè) bio 要傳送的第一個(gè)(512 字節(jié))扇區(qū)。被傳送的數(shù)據(jù)大小,以字節(jié)為位的大小。,驅(qū)動中可以使用bio_sectors(bio)宏獲得以扇區(qū)為單一組描述 bio 的標(biāo)志,如果這是一個(gè)寫請求,最低有效位被置位,可以使用bio_data_dir(bio)宏來獲得讀寫方向。分別表示包含在這個(gè) BIO 中要處理的不連續(xù)的物理內(nèi)存段的數(shù)目和考慮 DMA 重映像后的不連續(xù)的內(nèi)存段的數(shù)目。bio 的是一個(gè)稱為 bi_io_vec 的數(shù)組,它由 bio_vec 結(jié)構(gòu)體組成,bio_vec 結(jié)構(gòu)
44、體的定義如代碼13.6 所示。代碼13.6 bio_v ec 結(jié)構(gòu)體 我們不應(yīng)該直接bio 的 bio_vec 成員,而應(yīng)該使用 bio_for_each_segment()宏來進(jìn)行這項(xiàng)工作,可以用這個(gè)宏循環(huán)遍歷整個(gè) bio 中的每個(gè)段,這個(gè)宏的定義如代碼13.7 所示。代碼13.7 bio_for_each_segment 宏學(xué)院華清遠(yuǎn)見旗下品牌:1 #define_ _bio_for_each_segment(bvl,bio,i,start_idx)2 for (bvl = bio_iovec_idx(bio), (start_idx), i = (start_idx);3 i bi_vc
45、nt; 4bvl+, i+)56 #define bio_for_each_segment(bvl, bio, i) 1 struct bio_vec 2 3 struct page *bv_page; /* 頁指針 */4 unsigned int bv_len; /* 傳輸?shù)淖止?jié)數(shù) */5 unsigned int bv_offset; /* 偏移位置 */ 6 ;unsigned short bio_phys_segments; unsigned short bio_hw_segments;unsigned long bi_flags;unsigned int bi_size;secto
46、r_t bi_sector;29 bio_end_io_t *bi_end_io;30 atomic_t bi_cnt; 3132 void *bi_private;3334 bio_destructor_t *bi_destructor; /* destructor */ 35 ;Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動圖 13.2(a)所示為 request 隊(duì)列、request 與 bio 數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,13.2(b) 所示為 request、bio 和 bio_vec 數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,13.2(c)所示為 bio 與 bio_vec 數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系
47、,因此整個(gè)圖 13.2 遞歸地呈現(xiàn)了 request 隊(duì)列、request、bio 和bio_vec 這 4 個(gè)結(jié)構(gòu)體之間的關(guān)系。學(xué)院華清遠(yuǎn)見旗下品牌:7_ _bio_for_each_segment(bvl, bio, i, (bio)-bi_idxLinux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動圖 13.2 request 隊(duì)列、request、bio 和bio_vec 結(jié)構(gòu)體之間的關(guān)系內(nèi)核還提供了一組函數(shù)(宏)用于操作 bio:這個(gè)函數(shù)可用于獲得數(shù)據(jù)傳輸?shù)姆较蚴?READ 還是WRITE。這個(gè)函數(shù)可用于獲得目前的頁指針。這個(gè)函數(shù)返回操作對應(yīng)的當(dāng)前頁內(nèi)的偏移,通常塊 I/O
48、 操作本身就是頁對。這個(gè)函數(shù)返回當(dāng)前 bio_vec 要傳輸?shù)纳葏^(qū)數(shù)。這個(gè)函數(shù)返回?cái)?shù)據(jù)緩沖區(qū)的內(nèi)核虛擬地址。學(xué)院華清遠(yuǎn)見旗下品牌:char *bio_data(struct bio *bio) ;int bio_cur_sectors(struct bio *bio) ;int bio_offset(struct bio *bio) ;struct page *bio_page(struct bio *bio) ;int bio_data_dir(struct bio *bio);Linux 設(shè)備驅(qū)動開發(fā)詳解第 13 章、Linux 塊設(shè)備驅(qū)動這個(gè)函數(shù)返回一個(gè)內(nèi)核虛擬地址,這個(gè)地址可用于存取被
49、給定的 bio_vec指向的數(shù)據(jù)緩沖區(qū)。它也會驅(qū)動不應(yīng)該睡眠。中斷并返回一個(gè)原子 kmap,因此,在 bvec_kunmap_irq()被調(diào)用以前,這個(gè)函數(shù)是 bvec_kmap_irq()函數(shù)的“反函數(shù)”,它撤銷 bvec_kmap_irq()創(chuàng)建的映射。這個(gè)函數(shù)是對 bvec_kmap_irq()的包裝,它返回給定的 bio 的當(dāng)前 bio_vec的。這個(gè)函數(shù)通過 kmap_atomic()獲得返回給定 bio 的第 i 個(gè)緩沖區(qū)的虛擬地址。這個(gè)函數(shù)返還由_ _bio_kmap_atomic()獲得的內(nèi)核虛擬地址。另外,對 bio 的計(jì)數(shù)通過如下函數(shù)完成:13.2.4塊設(shè)備驅(qū)動與注銷塊設(shè)備驅(qū)動中的第一個(gè)工作通常是register_ bl
溫馨提示
- 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)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 注射頻率與鎮(zhèn)靜維持時(shí)間-洞察及研究
- 知識管理數(shù)字化路徑-洞察及研究
- 海溝生物基因資源-洞察及研究
- 跨平臺網(wǎng)絡(luò)切片的性能評估與性能對比-洞察闡釋
- 中藥肝腎復(fù)方抗腫瘤-洞察及研究
- 跨境旅游市場精準(zhǔn)營銷-洞察闡釋
- 數(shù)字化游客體驗(yàn)評價(jià)模型-洞察闡釋
- 玉米秸稈與鈍化劑對蔬菜生長的綜合影響研究
- 生物工程SRT培養(yǎng)模式中的導(dǎo)師制與雙輪驅(qū)動研究
- 智能分析驅(qū)動的體育賽事風(fēng)險(xiǎn)管理研究-洞察闡釋
- 教育政策學(xué)全套課件
- 2025至2030年中國高速公路廣告行業(yè)市場行情監(jiān)測及投資前景展望報(bào)告
- 識別心內(nèi)科護(hù)理高風(fēng)險(xiǎn)
- 2025年 嘉峪關(guān)市招聘編制外聘用制教師筆試試卷附答案
- 食品公司衛(wèi)生間管理制度
- 2025年數(shù)據(jù)挖掘和分析考試試卷及答案
- 口腔粘結(jié)系統(tǒng)
- 2025河南省豫地科技集團(tuán)社會招聘169人筆試參考題庫附帶答案詳解析集合
- 【北京市人社局】2025年北京市人力資源市場薪酬數(shù)據(jù)報(bào)告(一季度)
- 2024年09月2024秋季中國工商銀行湖南分行校園招聘620人筆試歷年參考題庫附帶答案詳解
- 牧場物語-礦石鎮(zhèn)的伙伴們-完全攻略
評論
0/150
提交評論