字符設(shè)備按照字節(jié)流的方式有序訪問,如鍵盤和串口。
目前成都創(chuàng)新互聯(lián)公司已為近1000家的企業(yè)提供了網(wǎng)站建設(shè)、域名、雅安服務(wù)器托管、網(wǎng)站托管、企業(yè)網(wǎng)站設(shè)計(jì)、山丹網(wǎng)站維護(hù)等服務(wù),公司將堅(jiān)持客戶導(dǎo)向、應(yīng)用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協(xié)力一起成長(zhǎng),共同發(fā)展。14.1 剖析一個(gè)塊設(shè)備
塊設(shè)備中最小的可尋址單元是扇區(qū)。扇區(qū)大小一般是2的整數(shù)倍,最常見的是512字節(jié)。扇區(qū)的大小是設(shè)備的物理屬性,扇區(qū)是所有塊設(shè)備的基本單元——塊設(shè)備無(wú)法對(duì)比它還小的單元進(jìn)行尋址和操作,盡管許多塊設(shè)備能夠一次對(duì)多個(gè)扇區(qū)進(jìn)行操作。很多CD-ROM盤的扇區(qū)都是2kB大小。
雖然物理磁盤尋址按照扇區(qū)級(jí)別進(jìn)行的,但是內(nèi)核執(zhí)行的所有磁盤操作都是按照塊進(jìn)行的。由于扇區(qū)是設(shè)備的最小可尋址單元,所以塊不能比扇區(qū)小,只能數(shù)倍于扇區(qū)大小。內(nèi)核要求塊的大小是2的倍數(shù)且不能超過頁(yè)的長(zhǎng)度。所以通常塊的大小是512字節(jié)、1KB或4KB。
14.2 緩沖區(qū)和緩沖區(qū)頭
當(dāng)一個(gè)塊被調(diào)人內(nèi)存時(shí),它要存儲(chǔ)在一個(gè)緩沖區(qū)中。每個(gè)緩沖區(qū)對(duì)應(yīng)一個(gè)塊它相當(dāng)與磁盤塊在內(nèi)存中的表示。每個(gè)緩沖區(qū)都有一個(gè)對(duì)應(yīng)的描述符。該描述符用buffer_head結(jié)構(gòu)體表示,稱作緩沖區(qū)頭,它包含了內(nèi)核操作緩沖區(qū)所需要的全部信息。
struct buffer_head{
usigned long b_state;//緩沖區(qū)狀態(tài)
struct buffer_head *b_this_page; //頁(yè)面中的緩沖區(qū)
struct page *b_page //緩沖區(qū)所在內(nèi)存物理頁(yè)
sector_t b_blocknr;//磁盤物理起始?jí)K號(hào)
size_t b_size ;// 映像大小
char *b_data ;//頁(yè)面內(nèi)數(shù)據(jù)指針,塊在內(nèi)存中的起始位置在b_data處,結(jié)束位置在b_data+b_size處
struct block_device *b_bdev; //管理的塊設(shè)備
bh_end_io_t *b_end_io; //io完成方法
void* b_private; //io完成方法
struct list_head b_assoc_buffers; //相關(guān)的映射鏈表
struct address_space *b_assoc_map; //相關(guān)的地址空間
atomic_t b_count; //緩沖區(qū)使用計(jì)數(shù)
};
14.3 bio 結(jié)構(gòu)體
目前內(nèi)核中塊I/O操作的基本容器有bio結(jié)構(gòu)體表示,該結(jié)構(gòu)體代表了正在現(xiàn)場(chǎng)的以片段鏈表形式組織的塊I/O操作。一個(gè)片段是一小塊連續(xù)的內(nèi)存緩沖區(qū)。這樣的話,就不需要保證單個(gè)緩沖區(qū)一定要連續(xù)。所以通過用片段來描述緩沖區(qū),及時(shí)一個(gè)緩沖區(qū)分散在內(nèi)存的多個(gè)位置上,bio結(jié)構(gòu)體也能對(duì)內(nèi)核保證IO操作的執(zhí)行。像這樣的向量IO就是所謂的聚合IO。
1 struct bio{
2 sector_t bi_sector //磁盤上相關(guān)的扇區(qū) 3 struct bio *bio_nex //請(qǐng)求鏈表 4 struct block_device *bi_dev;//相關(guān)的塊設(shè)備 5 unsigned long bi_flags; //狀態(tài)和命令標(biāo)志 6 unsigned long bi_rw; //讀還是寫 7 unsigned short bi_vcnt; //bio_vecs偏移個(gè)數(shù) 8 unsigned short bi_idx; //bio_io_vec當(dāng)前索引 9 unsigned short bi_phys_segments; //結(jié)合后的片段數(shù)目10 unsigned int bi_size; //IO計(jì)數(shù)11 unsigned int bi_seg_front_size; //第一個(gè)可合并段大小12 unsigned int bi_seg_back_size; //最后一個(gè)可合并段大小13 unsigned int bi_max_vecs; //bio_vecs數(shù)目上限14 unsigned int bi_comp_cpu; //結(jié)束cpu15 atomic_t bi_cnt ;//使用計(jì)數(shù)16 struct bio_vec *bi_io_vec; //bio_vecs鏈表17 bio_end_io_t *bi_end_io; //IO完成方法18 void *bi_private; //擁有者私有方法19 bio_destructor_r *bi_destructor;//撤銷方法20 struct bio_vec bi_inline_vecs[0] //內(nèi)嵌bio向量21 }
14.3.1 IO向量
bi_io_vec域指向一個(gè)bio_vec結(jié)構(gòu)體鏈表,該鏈表包含了一個(gè)特定IO操作所需要使用到的所有片段。每個(gè)bio_vec結(jié)構(gòu)都是一個(gè)形式為
在每個(gè)給定的塊IO操作中,bi_vcnt域用來描述bi_io_vec所指向的vio_vec數(shù)組中向量數(shù)目。當(dāng)塊IO操作執(zhí)行完畢后,bi_idx域指向數(shù)組的當(dāng)前索引。
每一個(gè)塊IO請(qǐng)求都通過一個(gè)bio結(jié)構(gòu)體表示。每個(gè)請(qǐng)求包含一個(gè)或多個(gè)塊。這些塊存儲(chǔ)在bio_vec結(jié)構(gòu)體數(shù)組中。這些結(jié)構(gòu)體描述了每個(gè)片段在物理頁(yè)中的實(shí)際位置,并且像向量一樣被組織在一起。IO操作的第一個(gè)片段有b_io_vec結(jié)構(gòu)體所指向,其他片段在其后依次放置,公有bi_vcnt個(gè)片段。當(dāng)塊IO開始執(zhí)行請(qǐng)求、需要使用各個(gè)片段時(shí),bi_idx域會(huì)不斷更新,從而總指向當(dāng)前片段。
bi_cnt域用于記錄bio結(jié)構(gòu)體的使用計(jì)數(shù),如果該域值減為0,就應(yīng)該撤銷該bio結(jié)構(gòu)體,并釋放它占用的內(nèi)存。
void bio_get(struct bio *bio);
void bio_put(struct bio *bio);
14.3 新老方法比較
1、bio結(jié)構(gòu)體很容易處理高端內(nèi)存,因?yàn)樗幚淼氖俏锢眄?yè)而不是直接指針
2、bio亦可以代表普通頁(yè)IO,同時(shí)也可以代表直接IO(不通過頁(yè)高速緩存的操作)
3、bio結(jié)構(gòu)體便于執(zhí)行分散-集中塊IO操作,操作中的數(shù)據(jù)可取自多個(gè)物理頁(yè)面
4、bio相比緩沖區(qū)頭屬于輕量級(jí)結(jié)構(gòu)體。因?yàn)樗恍枰瑝KIO操作所需要的信息,不用包含于緩沖區(qū)本省相關(guān)的不必要信息。
14.4 請(qǐng)求隊(duì)列
塊設(shè)備將他們掛起的塊IO請(qǐng)求保存在請(qǐng)求隊(duì)列中,該隊(duì)列由reques_queue結(jié)構(gòu)表示。通過內(nèi)核中像文件系統(tǒng)這樣高層的代碼將請(qǐng)求加入到隊(duì)列中。請(qǐng)求隊(duì)列只要不為空,隊(duì)列對(duì)應(yīng)的塊設(shè)備驅(qū)動(dòng)程序就會(huì)從隊(duì)列頭獲取請(qǐng)求,然后將其送入對(duì)應(yīng)的塊設(shè)備上去。
隊(duì)列其中的請(qǐng)求由結(jié)構(gòu)體request表示。因?yàn)橐粋€(gè)請(qǐng)求可能要操作多個(gè)連續(xù)的磁盤塊,所以每個(gè)請(qǐng)求可以由多個(gè)bio結(jié)構(gòu)組成。
14.5 IO調(diào)度程序