久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

[快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程詳解一

 guitarhua 2011-12-14

[快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程詳解一

      walfred已經(jīng)在[快速上手Linux設(shè)備驅(qū)動]之我看字符設(shè)備驅(qū)動一 文中詳細講解了linux下字符設(shè)備驅(qū)動,,并緊接著用四篇文章描述了Linux的設(shè)備模型,分別是總線,、設(shè)備,、驅(qū)動以及是類子系統(tǒng),。為什么要在現(xiàn)在才開始 講解塊設(shè)備驅(qū)動呢,,這里面是有原因,當初walfred自己學(xué)習(xí)時,,是先看的塊設(shè)備驅(qū)動然后才是linux設(shè)備模型,,導(dǎo)致理解上面有了點偏差,,現(xiàn)在我先將 linux設(shè)備模型拋出之后,,再敘述下linux下的塊設(shè)備驅(qū)動。

    [快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程分篇文章講解,,分別是:

    1,、[快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程詳解一 即是本文,主要講解塊設(shè)備去字符設(shè)備的區(qū)別以及塊設(shè)備驅(qū)動中牽涉到的幾個重要的結(jié)構(gòu)體,。

    2,、[快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程詳解二 講述了一個塊設(shè)備驅(qū)動的模板

1塊設(shè)備與字符設(shè)備的區(qū)別

1.1從字面上理解,塊設(shè)備和字符設(shè)備最大的區(qū)別在于讀寫數(shù)據(jù)的基本單元不同,。塊設(shè)備讀寫數(shù)據(jù)的基本單元為塊,,例如磁盤通常為一個sector(扇區(qū)),而字符設(shè)備的基本單元為字節(jié),。所以Linux中塊設(shè)備驅(qū)動往往為磁盤設(shè)備的驅(qū)動,,但是由于磁盤設(shè)備的 IO性能與CPU相比很差,因此,,塊設(shè)備的數(shù)據(jù)流往往會引入文件系統(tǒng)的Cache機制,。

1.2從實現(xiàn)角度來看,Linux為塊設(shè)備和字符設(shè)備提供了兩套機制,。字符設(shè)備實現(xiàn)的比較簡 單,,內(nèi)核例程和用戶態(tài)API一一對應(yīng),用戶層的Read函數(shù)直接對應(yīng)了內(nèi)核中的Read例程,,這種映射關(guān)系由字符設(shè)備的file_operations 護,。塊設(shè)備接口相對于字符設(shè)備復(fù)雜,read,、write API沒有直接到塊設(shè)備層,,而是直接到文件系統(tǒng)層,然后再由文件系統(tǒng)層發(fā)起讀寫請求,。

2相關(guān)結(jié)構(gòu)體

2.1 block_device_operations

      與字符設(shè)備驅(qū)動程序一樣,,塊設(shè)備驅(qū)動程序也包含一個在<linux/fs.h>中定義的block_device_operations結(jié)構(gòu),其定義如下所示,。

struct block_device_operations

{

    int (*open) (struct inode *, struct file *);

    int (*release) (struct inode *, struct file *);

    int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);

    long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);

    long (*compat_ioctl) (struct file *, unsigned, unsigned long);

    int (*direct_access) (struct block_device *, sector_t, unsigned long *);

    int (*media_changed) (struct gendisk *);

    int (*revalidate_disk) (struct gendisk *);

    int (*getgeo)(struct block_device *, struct hd_geometry *);

    struct module *owner;

};

      從該結(jié)構(gòu)的定義中,,可以看出塊設(shè)備并不提供read()write()等函數(shù)接口,。對塊設(shè)備的讀寫請求都是以異步方式發(fā)送到設(shè)備相關(guān)的request 隊列之中,。

      關(guān)于block_device_operations,,walfred曾在[快速上手Linux設(shè)備驅(qū)動]之一切皆是文件思想一文中有詳細敘述。

2.2 gendisk

      一個塊設(shè)備物理實體由一個gendisk結(jié)構(gòu)體來表示(在</linux/genhd.h>中定義),,每個gendisk可以支持多個分區(qū),。

      每個gendisk中包含了本物理實體的全部信息以及操作函數(shù)接口,。整個塊設(shè)備的注冊過程是圍繞gendisk來展開的,。在驅(qū)動程序中需要初始化的gendisk的一些成員如下所示。

struct gendisk

{

    int major;            /* 主設(shè)備號 */

    int first_minor;    /* 第一個次設(shè)備號 */

    int minors;          /* 次設(shè)備號個數(shù),,一個塊設(shè)備至少需要使用一個次設(shè)備號,而且塊設(shè)

                        備的每個分區(qū)都需要一個次設(shè)備號,,因此這個成員等于1,,則表明該塊

                        設(shè)備是不可被分區(qū)的,,否則可以包含minors – 1    個分區(qū),。*/

    char disk_name[32];        /* 塊設(shè)備名稱,,在/proc/partions中顯示 */

    struct hd_struct **part;    /* 分區(qū)表 */

    struct block_device_operations *fops;        /* 塊設(shè)備操作接口,,與字符設(shè)備的

                                                 file_operations結(jié)構(gòu)對應(yīng)*/

    struct request_queue *queue;    /* I/O請求隊列 */

    void *private_data;        /* 指向驅(qū)動程序私有數(shù)據(jù) */

    sector_t capacity;    /* 塊設(shè)備可包含的扇區(qū)數(shù) */

    …… /* 其他省略 */

};

2.3 request_queue request

      requestrequest_queue結(jié)構(gòu)體:Linux塊設(shè)備驅(qū)動中,使用request結(jié)構(gòu)體來表征等待進行的IO請求;并用request_queue來表征一個塊IO請求隊列.兩個結(jié)構(gòu)體的定義如下:

request結(jié)構(gòu)體

    struct request{

        struct list_head queuelist;

        unsigned long flags;

        sector_t sector;/*要傳輸?shù)南乱粋€扇區(qū)*/

        unsigned long nr_sectors;/*要傳送的扇區(qū)數(shù)目*/

        unsigned int current_nr_sector;/*當前要傳送的扇區(qū)*/

        sector_t hard_sector;/*要完成的下一個扇區(qū)*/

        unsigned long hard_nr_sectors;/*要被完成的扇區(qū)數(shù)目*/

        unsigned int hard_cur_sectors;/*當前要被完成的扇區(qū)數(shù)目*/

        struct bio* bio;/*請求的bio結(jié)構(gòu)體的鏈表*/

        struct bio* biotail;/*請求的bio結(jié)構(gòu)體的鏈表尾*/

        

        /*請求在屋里內(nèi)存中占據(jù)的不連續(xù)的段的數(shù)目*/

        unsigned short nr_phys_segments;

        unsigned short nr_hw_segments;

        int tag;

        char* buffer;/*傳送的緩沖區(qū),內(nèi)核的虛擬地址*/

        int ref_count;/*引用計數(shù)*/

        ...

    };

說明:

      request結(jié)構(gòu)體的主要成員包括:

        sector_t hard_sector;/*要完成的下一個扇區(qū)*/

        unsigned long hard_nr_sectors;/*要被完成的扇區(qū)數(shù)目*/

        unsigned int hard_cur_sectors;/*當前要被完成的扇區(qū)數(shù)目*/

        /*

         * 上述三個成員依次是第一個尚未傳輸?shù)纳葏^(qū),尚待完成的扇區(qū)數(shù),當前IO操作中待完成的扇區(qū)數(shù)

         * 但驅(qū)動中一般不會用到他們.而是下面的一組成員.

         */

        sector_t sector;/*要傳輸?shù)南乱粋€扇區(qū)*/

        unsigned long nr_sectors;/*要傳送的扇區(qū)數(shù)目*/

        unsigned int current_nr_sector;/*當前要傳送的扇區(qū)*/

        /* 

         * 這三個成員,以字節(jié)為單位.如果硬件的扇區(qū)大小不是512字節(jié).如字節(jié),則在開始對硬件進行操作之

         * ,應(yīng)先用4來除起始扇區(qū)號.前三個成員,與后三個成員的關(guān)系可以理解為"副本".

         */

 

 關(guān)于unsigned short nr_phys_segments:該成員表示相鄰的頁被合并后,這個請求在物理內(nèi)存中的段的數(shù)目.如果該設(shè)備支持SG(分散/聚合,scatter/gather),可根據(jù)該字段申請sizeof(scatterlist*) nr_phys_segments的內(nèi)存,并使用下面的函數(shù)進行DMA映射:

int blk_rq_map_sg(request_queue_t* q, struct request* rq, struct scatterlist *sg);

該函數(shù)與dma_map_sg()類似,返回scatterlist列表入口的數(shù)量.

      關(guān)于struct list_head queuelist:該成員用于鏈接這個請求到請求隊列的鏈表結(jié)構(gòu),函數(shù)blkdev_ dequeue_request()可用于從隊列中移除請求.rq_data_dir(struct request* req)可獲得數(shù)據(jù)傳送方向.返回0表示從設(shè)備讀取,否則表示寫向設(shè)備.

2.4 request_queue請求隊列

    struct request_queue{

        ...

        /*自旋鎖,保護隊列結(jié)構(gòu)體*/

        spinlock_t __queue_lock;

        spinlock_t* queue_lock;

        struct kobject kobj;/*隊列kobject*/

        /*隊列設(shè)置*/

        unsigned long nr_requests;/*最大的請求數(shù)量*/

        unsigned int  nr_congestion_on;

        unsigned int  nr_congestion_off;

        unsigned int  nr_batching;

        unsigned short max_sectors;/*最大扇區(qū)數(shù)*/

        unsigned short max_hw_sectors;

        unsigned short max_phys_sectors;/*最大的段數(shù)*/

        unsigned short max_hw_segments;

        unsigned short hardsect_size;/*硬件扇區(qū)尺寸*/

        unsigned int max_segment_size;/*最大的段尺寸*/

        unsigned long seg_boundary_mask;/*段邊界掩碼*/

        unsigned int dma_alignment;/*DMA傳送內(nèi)存對齊限制*/

        struct blk_queue_tag* queue_tags;

        atomic_t refcnt;/*引用計數(shù)*/

        unsigned int in_flight;

        unsigned int sg_timeout;

        unsigned int sg_reserved_size;

        int node;

        struct list_head drain_list;

        struct request* flush_rq;

        unsigned char ordered;

    };

      說明:請求隊列跟蹤等候的塊IO請求,它存儲用于描述這個設(shè)備能夠支持的請求的類型信息,他們的最大大小,多少不同的段可以進入一個請求,硬件扇區(qū)大小,對齊要求等參數(shù).其結(jié)果是:如果請求隊列被配置正確了,它不會交給該設(shè)備一個不能處理的請求.

      請求隊列還要實現(xiàn)一個插入接口,這個接口允許使用多個IO調(diào)度器,IO調(diào)度器以最優(yōu)性能的方式向驅(qū)動提交IO請求.大部分IO調(diào)度器是積累批量的IO請求,并將其排列為遞增/遞減的塊索引順序后,提交給驅(qū)動.另外,IO調(diào)度器還負責合并鄰近的請求,當一個新的IO請求被提交給調(diào)度器后,它會在隊列里搜尋包含鄰近的扇區(qū)的請求.如果找到一個,并且請求合理,調(diào)度器會將這兩個請求合并.

2.5I/O

      通常一個bio對應(yīng)一個IO請求.IO調(diào)度算法可將連續(xù)的bio合并成一個請求.所以一個請求包含多個bio.

    struct bio{

        sector_t bi_sector;/*要傳送的第一個扇區(qū)*/

        struct bio* bi_next;/*下一個bio*/

        struct block_device* bi_bdev;

        unsigned long bi_flags;

        /*如果是一個寫請求,最低有效位被置位,可使用bio_data_dir(bio)宏來獲取讀寫方向*/

        unsigned long bi_rw;/*地位表示R/W方向,高位表示優(yōu)先級*/

        unsigned short bi_vcnt;/*bio_vec數(shù)量*/

        unsigned short bi_idx; /*當前bvl_vec索引*/

        unsigned short bi_phys_segments;/*不相鄰的物理段的數(shù)目*/

        unsigned short bi_hw_segments;/*物理合并和DMA remap合并后不相鄰的物理扇區(qū)*/

        unsigned int bi_size;

        /*被傳送的數(shù)據(jù)大小(byte),bio_sector(bio)獲取扇區(qū)為單位的大小*/

        /*為了明了最大的hw尺寸,考慮bio中第一個和最后一個虛擬的可合并的段的尺寸*/

        unsigned int bi_hw_front_size;

        unsigned int bi_hw_back_size;

        unsigned int bi_max_vecs;/*能持有的最大bvl_vecs數(shù)*/

        struct bio_vec* bio_io_vec;/*實際的vec列表*/

        bio_end_io_t* bio_end_io;

        atomic_t bi_cnt;

        void* bi_private;

        bio_destructor_t* bi_destructor;

    };

      //結(jié)構(gòu)體包含三個成員

    struct bio_vec{

        struct page* bv_page;//頁指針

        unsigned int bv_len;//傳送的字節(jié)數(shù)

        unsigned int bv_offset;//偏移位置

    };

 

/*一般不直接訪問biobio_vec成員,而使用bio_for_each_segment()宏進行操作.

 *該宏循環(huán)遍歷整個bio中的每個段.

 */

    #define __bio_for_each_segment(bvl, bio, i, start_idx)\

             for(

                bvl = bio_iovec_idx((bio),(start_idx)),i = (start_idx);\

                i <(bio)->bi_vcnt;\

                bvl++, i++\

             )

    #define bio_for_each_segment(bvl, bio, i)\

              __bio_for_each_segment(bvl, bio, i, (bio)->bi_idx)

      在內(nèi)核中,提供了一組函數(shù)()用于操作bio:

    int bio_data_dir(struct bio* bio);

    該函數(shù)用于獲得數(shù)據(jù)傳送方向.

    struct page* bio_page(struct bio* bio);

    該函數(shù)用于獲得目前的頁指針.

    int bio_offset(struct bio* bio);

      該函數(shù)返回操作對應(yīng)的當前頁的頁內(nèi)偏移,通常塊IO操作本身就是頁對齊的.

    int bio_cur_sectors(struct bio* bio);

      該函數(shù)返回當前bio_vec要傳輸?shù)纳葏^(qū)數(shù).

    char* bio_data(struct bio* bio);

      該函數(shù)返回數(shù)據(jù)緩沖區(qū)的內(nèi)核虛擬地址.

    char* bvec_kmap_irq(struct bio_vec* bvec, unsigned long* offset);

    該函數(shù)也返回一個內(nèi)核虛擬地址此地址可用于存取被給定的bio_vec入口指向的數(shù)據(jù)緩沖區(qū).同時會屏蔽中斷并返回一個原子kmap,因此,在此函數(shù)調(diào)用之前,驅(qū)動不應(yīng)該是睡眠狀態(tài).

    void bvec_kunmap_irq(char* buffer, unsigned long flags);

    該函數(shù)撤銷函數(shù)bvec_kmap_irq()創(chuàng)建的內(nèi)存映射.

    char* bio_kmap_irq(struct bio* bio, unsigned long* flags);

      該函數(shù)是對bvec_kmap_irq函數(shù)的封裝,它返回給定的比偶的當前bio_vec入口的映射.

    char* __bio_kmap_atomic(struct bio* bio, int i, enum km_type type);

    該函數(shù)是通過kmap_atomic()獲得返回給定bio的第i個緩沖區(qū)的虛擬地址.

    void __bio_kunmap_atomic(char* addr, enum km_type type);

      該函數(shù)返還由函數(shù)__bio_kmap_atomic()獲得的內(nèi)核虛擬地址給系統(tǒng).

    void bio_get(struct bio* bio);

    void bio_put(struct bio* bio);

      上面兩個函數(shù)分別完成對bio的引用和引用釋放.

      下圖可以體現(xiàn)出bio/request/request_queue/bio_vec四個結(jié)構(gòu)體之間的關(guān)系.

 

1

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多