Linux设备驱动--块设备(二)之相关结构体
上回最后面介紹了相關(guān)數(shù)據(jù)結(jié)構(gòu),下面再詳細(xì)介紹
塊設(shè)備對(duì)象結(jié)構(gòu) block_device
內(nèi)核用結(jié)構(gòu)block_device實(shí)例代表一個(gè)塊設(shè)備對(duì)象,如:整個(gè)硬盤(pán)或特定分區(qū)。如果該結(jié)構(gòu)代表一個(gè)分區(qū),則其成員bd_part指向設(shè)備的分區(qū)結(jié)構(gòu)。如果該結(jié)構(gòu)代表設(shè)備,則其成員bd_disk指向設(shè)備的通用硬盤(pán)結(jié)構(gòu)gendisk
當(dāng)用戶打開(kāi)塊設(shè)備文件時(shí),內(nèi)核創(chuàng)建結(jié)構(gòu)block_device實(shí)例,設(shè)備驅(qū)動(dòng)程序還將創(chuàng)建結(jié)構(gòu)gendisk實(shí)例,分配請(qǐng)求隊(duì)列并注冊(cè)結(jié)構(gòu)block_device實(shí)例。
塊設(shè)備對(duì)象結(jié)構(gòu)block_device列出如下(在include/Linux/fs.h中)
[cpp]?view plaincopy print?
通用硬盤(pán)結(jié)構(gòu) gendisk
結(jié)構(gòu)體gendisk代表了一個(gè)通用硬盤(pán)(generic hard disk)對(duì)象,它存儲(chǔ)了一個(gè)硬盤(pán)的信息,包括請(qǐng)求隊(duì)列、分區(qū)鏈表和塊設(shè)備操作函數(shù)集等。塊設(shè)備驅(qū)動(dòng)程序分配結(jié)構(gòu)gendisk實(shí)例,裝載分區(qū)表,分配請(qǐng)求隊(duì)列并填充結(jié)構(gòu)的其他域。
支持分區(qū)的塊驅(qū)動(dòng)程序必須包含 <linux/genhd.h> 頭文件,并聲明一個(gè)結(jié)構(gòu)gendisk,內(nèi)核還維護(hù)該結(jié)構(gòu)實(shí)例的一個(gè)全局鏈表gendisk_head,通過(guò)函數(shù)add_gendisk、del_gendisk和get_gendisk維護(hù)該鏈表。
結(jié)構(gòu)gendisk列出如下(在include/linux/genhd.h中):
[cpp]?view plaincopy print?
Linux內(nèi)核提供了一組函數(shù)來(lái)操作gendisk,主要包括:
分配gendisk
struct gendisk *alloc_disk(int minors);
minors 參數(shù)是這個(gè)磁盤(pán)使用的次設(shè)備號(hào)的數(shù)量,一般也就是磁盤(pán)分區(qū)的數(shù)量,此后minors不能被修改。
增加gendisk
gendisk結(jié)構(gòu)體被分配之后,系統(tǒng)還不能使用這個(gè)磁盤(pán),需要調(diào)用如下函數(shù)來(lái)注冊(cè)這個(gè)磁盤(pán)設(shè)備:
void add_disk(struct gendisk *gd);
特別要注意的是對(duì)add_disk()的調(diào)用必須發(fā)生在驅(qū)動(dòng)程序的初始化工作完成并能響應(yīng)磁盤(pán)的請(qǐng)求之后。
?釋放gendisk
當(dāng)不再需要一個(gè)磁盤(pán)時(shí),應(yīng)當(dāng)使用如下函數(shù)釋放gendisk:
void del_gendisk(struct gendisk *gd);
設(shè)置gendisk容量
void set_capacity(struct gendisk *disk, sector_t size);
塊設(shè)備中最小的可尋址單元是扇區(qū),扇區(qū)大小一般是2的整數(shù)倍,最常見(jiàn)的大小是512字節(jié)。扇區(qū)的大小是設(shè)備的物理屬性,扇區(qū)是所有塊設(shè)備的基本單元,塊設(shè)備 無(wú)法對(duì)比它還小的單元進(jìn)行尋址和操作,不過(guò)許多塊設(shè)備能夠一次就傳輸多個(gè)扇區(qū)。雖然大多數(shù)塊設(shè)備的扇區(qū)大小都是512字節(jié),不過(guò)其它大小的扇區(qū)也很常見(jiàn), 比如,很多CD-ROM盤(pán)的扇區(qū)都是2K大小。不管物理設(shè)備的真實(shí)扇區(qū)大小是多少,內(nèi)核與塊設(shè)備驅(qū)動(dòng)交互的扇區(qū)都以512字節(jié)為單位。因此,set_capacity()函數(shù)也以512字節(jié)為單位。
分區(qū)結(jié)構(gòu)hd_struct代表了一個(gè)分區(qū)對(duì)象,它存儲(chǔ)了一個(gè)硬盤(pán)的一個(gè)分區(qū)的信息,驅(qū)動(dòng)程序初始化時(shí),從硬盤(pán)的分區(qū)表中提取分區(qū)信息,存放在分區(qū)結(jié)構(gòu)實(shí)例中。
塊設(shè)備操作函數(shù)集結(jié)構(gòu) block_device_operations
字符設(shè)備通過(guò) file_operations 操作結(jié)構(gòu)使它們的操作對(duì)系統(tǒng)可用. 一個(gè)類(lèi)似的結(jié)構(gòu)用在塊設(shè)備上是 struct block_device_operations,
定義在 <linux/fs.h>.?
int (*open)(struct inode *inode, struct file *filp);?
int (*release)(struct inode *inode, struct file *filp);?
就像它們的字符驅(qū)動(dòng)對(duì)等體一樣工作的函數(shù); 無(wú)論何時(shí)設(shè)備被打開(kāi)和關(guān)閉都調(diào)用它們. 一個(gè)字符驅(qū)動(dòng)可能通過(guò)啟動(dòng)設(shè)備或者鎖住門(mén)(為可移出的介質(zhì))來(lái)響應(yīng)一個(gè) open 調(diào)用. 如果你將介質(zhì)鎖入設(shè)備, 你當(dāng)然應(yīng)當(dāng)在 release 方法中解鎖.
int (*ioctl)(struct inode *inode, struct file *filp,?
????????????????????????? unsigned int cmd, unsigned long arg);?
實(shí)現(xiàn) ioctl 系統(tǒng)調(diào)用的方法. 但是, 塊層首先解釋大量的標(biāo)準(zhǔn)請(qǐng)求; 因此大部分的塊驅(qū)動(dòng) ioctl 方法相當(dāng)短.
PS:在block_device_operations中沒(méi)有實(shí)際讀或?qū)憯?shù)據(jù)的函數(shù). 在塊 I/O 子系統(tǒng), 這些操作由請(qǐng)求函數(shù)處理
請(qǐng)求結(jié)構(gòu)request
結(jié)構(gòu)request代表了掛起的I/O請(qǐng)求,每個(gè)請(qǐng)求用一個(gè)結(jié)構(gòu)request實(shí)例描述,存放在請(qǐng)求隊(duì)列鏈表中,由電梯算法進(jìn)行排序,每個(gè)請(qǐng)求包含1個(gè)或多個(gè)結(jié)構(gòu)bio實(shí)例
[cpp]?view plaincopy print??request結(jié)構(gòu)體的主要成員包括:
?sector_t hard_sector;?
unsigned long hard_nr_sectors;?
unsigned int hard_cur_sectors;?
上述3個(gè)成員標(biāo)識(shí)還未完成的扇區(qū),hard_sector是第1個(gè)尚未傳輸?shù)纳葏^(qū),hard_nr_sectors是尚待完成的扇區(qū)數(shù),hard_cur_sectors是并且當(dāng)前I/O操作中待完成的扇區(qū)數(shù)。這些成員只用于內(nèi)核塊設(shè)備層,驅(qū)動(dòng)不應(yīng)當(dāng)使用它們。
?sector_t sector;?
unsigned long nr_sectors;?
unsigned int current_nr_sectors;?
驅(qū)動(dòng)中會(huì)經(jīng)常與這3個(gè)成員打交道,這3個(gè)成員在內(nèi)核和驅(qū)動(dòng)交互中發(fā)揮著重大作用。它們以512字節(jié)大小為1個(gè)扇區(qū),如果硬件的扇區(qū)大小不是512字節(jié),則需要進(jìn)行相應(yīng)的調(diào)整。例如,如果硬件的扇區(qū)大小是2048字節(jié),則在進(jìn)行硬件操作之前,需要用4來(lái)除起始扇區(qū)號(hào)。
?hard_sector、hard_nr_sectors、hard_cur_sectors與sector、nr_sectors、current_nr_sectors之間可認(rèn)為是“副本”關(guān)系。
struct bio *bio;?
bio是這個(gè)請(qǐng)求中包含的bio結(jié)構(gòu)體的鏈表,驅(qū)動(dòng)中不宜直接存取這個(gè)成員,而應(yīng)該使用后文將介紹的rq_for_each_bio()。
請(qǐng)求隊(duì)列結(jié)構(gòu)request_queue
每個(gè)塊設(shè)備都有一個(gè)請(qǐng)求隊(duì)列,每個(gè)請(qǐng)求隊(duì)列單獨(dú)執(zhí)行I/O調(diào)度,請(qǐng)求隊(duì)列是由請(qǐng)求結(jié)構(gòu)實(shí)例鏈接成的雙向鏈表,鏈表以及整個(gè)隊(duì)列的信息用結(jié)構(gòu)request_queue描述,稱(chēng)為請(qǐng)求隊(duì)列對(duì)象結(jié)構(gòu)或請(qǐng)求隊(duì)列結(jié)構(gòu)。它存放了關(guān)于掛起請(qǐng)求的信息以及管理請(qǐng)求隊(duì)列(如:電梯算法)所需要的信息。結(jié)構(gòu)成員request_fn是來(lái)自設(shè)備驅(qū)動(dòng)程序的請(qǐng)求處理函數(shù)。
請(qǐng)求隊(duì)列結(jié)構(gòu)request_queue列出如下(在/include/linux/blk_dev.h中)
太長(zhǎng)了,此處略,其實(shí)也看不懂,- -#
Bio結(jié)構(gòu)
通常1個(gè)bio對(duì)應(yīng)1個(gè)I/O請(qǐng)求,IO調(diào)度算法可將連續(xù)的bio合并成1個(gè)請(qǐng)求。所以,1個(gè)請(qǐng)求可以包含多個(gè)bio。
內(nèi)核中塊I/O操作的基本容器由bio結(jié)構(gòu)體表示,定義 在<linux/bio.h>中,該結(jié)構(gòu)體代表了正在現(xiàn)場(chǎng)的(活動(dòng)的)以片段(segment)鏈表形式組織的塊I/O操作。一個(gè)片段是一小 塊連續(xù)的內(nèi)存緩沖區(qū)。這樣的好處就是不需要保證單個(gè)緩沖區(qū)一定要連續(xù)。所以通過(guò)片段來(lái)描述緩沖區(qū),即使一個(gè)緩沖區(qū)分散在內(nèi)存的多個(gè)位置上,bio結(jié)構(gòu)體也 能對(duì)內(nèi)核保證I/O操作的執(zhí)行,這樣的就叫做聚散I/O.
bio為通用層的主要數(shù)據(jù)結(jié)構(gòu),既描述了磁盤(pán)的位置,又描述了內(nèi)存的位置,是上層內(nèi)核vfs與下層驅(qū)動(dòng)的連接紐帶
內(nèi)存數(shù)據(jù)段結(jié)構(gòu)bio_vec
?????? 結(jié)構(gòu)bio_vec代表了內(nèi)存中的一個(gè)數(shù)據(jù)段,數(shù)據(jù)段用頁(yè)、偏移和長(zhǎng)度描
述。I/O需要執(zhí)行的內(nèi)存位置用段表示,結(jié)構(gòu)bio指向了一個(gè)段的數(shù)組。
結(jié)構(gòu)bio_vec列出如下(在include/linux/bio.h中):
struct bio_vec {
?????? struct page???? *bv_page;?? /*數(shù)據(jù)段所在的頁(yè)*/
?????? unsigned short? bv_len;???? /*數(shù)據(jù)段的長(zhǎng)度*/
?????? unsigned short? bv_offset;? /*數(shù)據(jù)段頁(yè)內(nèi)偏移*/
};
塊設(shè)備各個(gè)結(jié)構(gòu)體間關(guān)系
轉(zhuǎn)載于:https://www.cnblogs.com/Ph-one/p/6435916.html
總結(jié)
以上是生活随笔為你收集整理的Linux设备驱动--块设备(二)之相关结构体的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 1283 最小周长
- 下一篇: Linux 网络子系统之NAPI书签