国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Linux塊設(shè)備驅(qū)動詳解
<機械硬盤>
a:磁盤結(jié)構(gòu)
    傳統(tǒng)的機械硬盤一般為3.5英寸硬盤,并由多個圓形蝶片組成,每個蝶片擁有獨立的機械臂和磁頭,每個堞片的圓形平面被劃分了不同的同心圓,每一個同心圓稱為一個磁道,位于最外面的道的周長最長稱為外道,最里面的道稱為內(nèi)道,通常硬盤廠商會將圓形蝶片最靠里面的一些內(nèi)道(速度較慢,影響性能)封裝起來不用;道又被劃分成不同的塊單元稱為扇區(qū),每個道周長不同,現(xiàn)代硬盤不同長度的道劃分出來的扇區(qū)數(shù)也是不相同的,而磁頭不工作的時候一般位于內(nèi)道,如果追求響應(yīng)時間,則數(shù)據(jù)可存儲在硬盤的內(nèi)道,如果追求大的吞吐量,則數(shù)據(jù)應(yīng)存儲在硬盤的外道;
 
注意:;一個弧道被劃分成多個段,每一個段就是一個扇區(qū)
b:磁盤訪問
------SATA硬盤實現(xiàn)的是串行ATA協(xié)議,ATA下盤命令中記錄有LBA(Logic Block Address)起始地址和扇區(qū)數(shù);LBA地址實際上是一個ATA協(xié)議邏輯地址,硬盤的固件會解析收到的ATA命令,并將要訪問的LBA地址映射至某個磁道中的某個物理塊即扇區(qū)。操作系統(tǒng)暫可認為LBA地址就是硬盤的物理地址。
c:扇區(qū)
------硬盤的基本訪問單位,扇區(qū)的大小一般是512B(對于現(xiàn)在的有些磁盤的扇區(qū)>512B,比如光盤的一個扇區(qū)就是2048B,Linux將其看成4個扇區(qū),無非就是需要完成4次的讀寫)。
d:塊
------扇區(qū)是硬件傳輸數(shù)據(jù)的基本單位,硬件一次傳輸一個扇區(qū)的數(shù)據(jù)到內(nèi)存中。但是和扇區(qū)不同的是,塊是虛擬文件系統(tǒng)傳輸數(shù)據(jù)的基本單位。在Linux中,塊的大小必須是2的冪,但是不能超過一個頁的大?。?k)。(在X86平臺,一個頁的大小是4094個字節(jié),所以塊大小可以是512,1024,2048,4096
e:段
------主要為了做scatter/gather DMA操作使用,同一個物理頁面中的在硬盤存儲介質(zhì)上連續(xù)的多個塊組成一個。段的大小只與塊有關(guān),必須是塊的整數(shù)倍。所以塊通常包括多個扇區(qū),段通常包括多個塊,物理段通常包括多個段;在內(nèi)核中由結(jié)構(gòu)struct bio_vec來描述,多個段的信息存放于struct bio結(jié)構(gòu)中的bio_io_vec指針數(shù)組中,段數(shù)組在后續(xù)的塊設(shè)備處理流程中會被合并成物理段,段結(jié)構(gòu)定義如下:
struct bio_vec {
       struct page      *bv_page;  // 段所在的物理頁面結(jié)構(gòu),即bh->b_page
       unsigned int    bv_len;    // 段的字節(jié)數(shù),即bh->b_size
       unsigned int    bv_offset;  // 段在bv_page頁面中的偏移,即bh->b_data
};
f:文件塊
------大小定義和文件系統(tǒng)塊一樣;只是相對于文件的一個偏移邏輯塊,需要通過具體文件系統(tǒng)中的此文件對應(yīng)的inode所記錄的間接塊信息,換算成對應(yīng)的文件系統(tǒng)塊;此做法是為了將一個文件的內(nèi)容存于硬盤的不同位置,以提高訪問速度;即一個文件的內(nèi)容在硬盤是一般是不連續(xù)的;EXT2中,ext2_get_block()完成文件塊到文件系統(tǒng)塊的映射。
g:總結(jié)
------扇區(qū)磁盤的物理特性決定;塊緩沖區(qū)由內(nèi)核代碼決定;緩沖區(qū)決定,是塊緩沖區(qū)大小的整數(shù)倍(但是不能超過一個頁)。三者關(guān)系如下:
 
所以:扇區(qū)(512)≤塊≤頁(4096) 塊=n*扇區(qū)(n為整數(shù))
注意:段(struct bio_vec{})由多個塊組成,一個段就是一個內(nèi)存頁(如果一個塊是兩個扇區(qū)大小,也就是1024B,那么一個段的大小可以是1024,2018,3072,4096,也就是說段的大小只與塊有關(guān),而且是整數(shù)倍)。Linux系統(tǒng)一次讀取磁盤的大小是一個塊,而不是一個扇區(qū),塊設(shè)備驅(qū)動由此得名。
<塊設(shè)備處理過程>
a:linux 內(nèi)核中,塊設(shè)備將數(shù)據(jù)存儲與固定的大小的塊中,每個塊都有自己的固定地址。Linux內(nèi)核中塊設(shè)備和其他模塊的關(guān)系如下。
a:塊設(shè)備的處理過程涉及Linux內(nèi)核中的很多模塊,下面簡單描述之間的處理過過程。
(1)當(dāng)一個用戶程序要向磁盤寫入數(shù)據(jù)時,會發(fā)發(fā)出write()系統(tǒng)調(diào)用給內(nèi)核。
(2)內(nèi)核會調(diào)用虛擬文件系統(tǒng)相應(yīng)的函數(shù),將需要寫入發(fā)文件描述符和文件內(nèi)容指針傳遞給該函數(shù)。
(3)內(nèi)核需要確定寫入磁盤的位置,通過映射層知道需要寫入磁盤的哪一塊。
(4)根據(jù)磁盤的文件系統(tǒng)的類型,調(diào)用不同文件格式的寫入函數(shù),江蘇數(shù)據(jù)發(fā)送給通用塊層(比如ext2和ext3文件系統(tǒng)的寫入函數(shù)是不同的,這些函數(shù)由內(nèi)核開發(fā)者實現(xiàn),驅(qū)動開發(fā)者不用實現(xiàn)這類函數(shù))
(5)數(shù)據(jù)到達通用塊層后,就對塊設(shè)備發(fā)出寫請求。內(nèi)核利用通用塊層的啟動I/O調(diào)度器,對數(shù)據(jù)進行排序。
(6)同用塊層下面是"I/O調(diào)度器"。調(diào)度器作用是把物理上相鄰的讀寫合并在一起,這樣可以加快訪問速度。
(7)最后快設(shè)備驅(qū)動向磁盤發(fā)送指令和數(shù)據(jù),將數(shù)據(jù)寫入磁盤。

<基本概念>

a:塊設(shè)備(block device)
-----是一種具有一定結(jié)構(gòu)的隨機存取設(shè)備,對這種設(shè)備的讀寫是按塊進行的,他使用緩沖區(qū)來存放暫時的數(shù)據(jù),待條件成熟后,從緩存一次性寫入設(shè)備或者從設(shè)備一次性讀到緩沖區(qū)。
b:字符設(shè)備(Character device)
---是一個順序的數(shù)據(jù)流設(shè)備,對這種設(shè)備的讀寫是按字符進行的,而且這些字符是連續(xù)地形成一個數(shù)據(jù)流。他不具備緩沖區(qū),所以對這種設(shè)備的讀寫是實時的。
<linux 塊設(shè)備驅(qū)動架構(gòu)圖>
 a:架構(gòu)分析
)struct bio
------當(dāng)一個進程被Read時,首先讀取cache 中有沒有相應(yīng)的文件,這個cache由一個buffer_head結(jié)構(gòu)讀取。如果沒有,文件系統(tǒng)就會利用塊設(shè)備驅(qū)動去讀取磁盤扇區(qū)的數(shù)據(jù)。于是read()函數(shù)就會初始化一個bio結(jié)構(gòu)體,并提交給通用塊層。通常用一個bio結(jié)構(gòu)體來對應(yīng)一個I/O請求。
(1)內(nèi)核結(jié)構(gòu)如下:
struct bio {
sector_t bi_sector; /* 要傳輸?shù)牡谝粋€扇區(qū) */
struct bio *bi_next; /* 下一個 bio */
struct block_device*bi_bdev;
unsigned long bi_flags; /* 狀態(tài)、命令等 */
unsigned long bi_rw; /* 低位表示 READ/WRITE,高位表示優(yōu)先級*/

unsigned short bi_vcnt; /* bio_vec 數(shù)量 */
unsigned short bi_idx; /* 當(dāng)前 bvl_vec 索引 */

/* 執(zhí)行物理地址合并后 sgement 的數(shù)目 */
unsigned short bi_phys_segments;

unsigned int bi_size;

/* 為了明了最大的 segment 尺寸,我們考慮這個 bio 中第一個和最后一個
可合并的 segment 的尺寸 */
unsigned int bi_hw_front_size;
unsigned int bi_hw_back_size;

unsigned int bi_max_vecs; /* 我們能持有的最大 bvl_vecs 數(shù) */
unsigned int bi_comp_cpu; /* completion CPU */

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

bio_end_io_t *bi_end_io;
atomic_t bi_cnt;

void *bi_private;
#if defined(CONFIG_BLK_DEV_INTEGRITY)
struct bio_integrity_payload *bi_integrity; /* 數(shù)據(jù)完整性 */
#endif

bio_destructor_t *bi_destructor; /* 析構(gòu) */
};
(2)bio的核心是一個被稱為bi_io_vec的數(shù)組,它由bio_vec組成(也就是說bio由許多bio_vec組成)。內(nèi)核定義如下:
struct bio_vec {
struct page *bv_page; /* 頁指針 */
unsigned int bv_len; /* 傳輸?shù)淖止?jié)數(shù) */
unsigned int bv_offset; /* 偏移位置 */
};
bio_vec描述一個特定的片段,片段所在的物理頁,塊在物理頁中的偏移頁,整個bio_io_vec結(jié)構(gòu)表示一個完整的緩沖區(qū)。當(dāng)一個塊被調(diào)用內(nèi)存時,要儲存在一個緩沖區(qū),每個緩沖區(qū)與一個塊對應(yīng),所以每一個緩沖區(qū)獨有一個對應(yīng)的描述符,該描述符用buffer_head結(jié)構(gòu)表示:
  • struct buffer_head 

  •     unsigned long b_state; /* buffer state bitmap (see above) */

  •     struct buffer_head *b_this_page/* circular list of page's buffers */

  •     struct page *b_page /* the page this bh is mapped to */

  •     sector_t b_blocknr;                          /* start block number */

  •     size_t b_size;                                   /* size of mapping */

  •     char *b_data;             /* pointer to data within the page */


  •    struct block_device *b_bdev;

  •    bh_end_io_t *b_end_io;                   /* I/O completion */

  •   void *b_private;                              /* reserved for b_end_io */

  •   struct list_head b_assoc_buffers;     /* associated with another mapping */

  •   struct address_space *b_assoc_map;    /* mapping this buffer is

  •                                                              associated with */

  •    atomic_t b_count;                          /* users using this buffer_head */

  • };

(3)bio和buffer_head之間的使用關(guān)系
核心ll_rw_block函數(shù):
  • void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])

  • {

  •     int i;

  •     for (= 0; i < nr; i ) {

  •         struct buffer_head *bh = bhs[i];


  •         if (!trylock_buffer(bh))

  •             continue;

  •         if (rw == WRITE) {

  •             if (test_clear_buffer_dirty(bh)) {

  •                 bh->b_end_io = end_buffer_write_sync;

  •                 get_bh(bh);

  •                 submit_bh(WRITE, bh);

  •                 continue;

  •             }

  •         } else {

  •             if (!buffer_uptodate(bh)) {

  •                 bh->b_end_io = end_buffer_read_sync;

  •                 get_bh(bh);

  •                 submit_bh(rw, bh);

  •                 continue;

  •             }

  •         }

  •         unlock_buffer(bh);

  •     }

  • }

核心submit_bh()函數(shù):
 
  • int submit_bh(int rw, struct buffer_head * bh)

  • {

  •     struct bio *bio;

  •     int ret = 0;


  •     BUG_ON(!buffer_locked(bh));

  •     BUG_ON(!buffer_mapped(bh));

  •     BUG_ON(!bh->b_end_io);

  •     BUG_ON(buffer_delay(bh));

  •     BUG_ON(buffer_unwritten(bh));


  •     /*

  •      * Only clear out a write error when rewriting

  •      */

  •     if (test_set_buffer_req(bh) && (rw & WRITE))

  •         clear_buffer_write_io_error(bh);


  •     /*

  •      * from here on down, it's all bio -- do the initial mapping,

  •      * submit_bio -> generic_make_request may further map this bio around

  •      */

  •     bio = bio_alloc(GFP_NOIO, 1);

  •     bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);

  •     bio->bi_bdev = bh->b_bdev;

  •     bio->bi_io_vec[].bv_page = bh->b_page;

  •     bio->bi_io_vec[].bv_len = bh->b_size;

  •     bio->bi_io_vec[].bv_offset = bh_offset(bh);

  •     bio->bi_vcnt = 1;

  •     bio->bi_idx = 0;

  •     bio->bi_size = bh->b_size;

  •     bio->bi_end_io = end_bio_bh_io_sync;

  •     bio->bi_private = bh;

  •     bio_get(bio);

  •     submit_bio(rw, bio);


  •     if (bio_flagged(bio, BIO_EOPNOTSUPP))

  •         ret = -EOPNOTSUPP;

  •     bio_put(bio);

  •     return ret;

  • }

這個函數(shù)主要是調(diào)用submit_bio,最終調(diào)用generic_make_request去完成將bio傳遞給驅(qū)動去處理。如下所示:
 
  • void generic_make_request(struct bio *bio)

  • {

  •     struct bio_list bio_list_on_stack;


  •     if (!generic_make_request_checks(bio))

  •         return;


  •     if (current->bio_list) {

  •         bio_list_add(current->bio_list, bio);

  •         return;

  •     }


  •     BUG_ON(bio->bi_next);

  •     bio_list_init(&bio_list_on_stack);

  •     current->bio_list = &bio_list_on_stack;

  •     do {

  •         struct request_queue *= bdev_get_queue(bio->bi_bdev);


  •         q->make_request_fn(q, bio);

  •         bio = bio_list_pop(current->bio_list);

  •     } while (bio);

  •     current->bio_list = NULL; /* deactivate */

  • }

這個函數(shù)主要是取出塊設(shè)備相應(yīng)的隊列中的每個設(shè)備,在調(diào)用塊設(shè)備驅(qū)動的make_request,如果沒有指定make_request就調(diào)用內(nèi)核默認的__make_request,這個函數(shù)主要作用就是調(diào)用I/O調(diào)度算法將bio合并,或插入到隊列中合適的位置中去。


2)struct request
------提交工作由submit_bio()去完成,通用層在調(diào)用相應(yīng)的設(shè)備IO調(diào)度器,這個調(diào)度器的調(diào)度算法,將這個bio合并到已經(jīng)存在的request中,或者創(chuàng)建一個新的request,并將創(chuàng)建的插入到請求隊列中。最后就剩下塊設(shè)備驅(qū)動層來完成后面的所有工作。(Linux系統(tǒng)中,對塊設(shè)備的IO請求,都會向塊設(shè)備驅(qū)動發(fā)出一個請求,在驅(qū)動中用request結(jié)構(gòu)體描述)
內(nèi)核結(jié)構(gòu)如下:

struct request {
struct list_head queuelist;
struct call_single_data csd;
int cpu;

struct request_queue *q;

unsigned int cmd_flags;
enum rq_cmd_type_bits cmd_type;
unsigned long atomic_flags;

/* 維護 I/O submission 的 BIO 遍歷狀態(tài)
* hard_開頭的成員僅用于塊層內(nèi)部,驅(qū)動不應(yīng)該改變它們
*/

sector_t sector; /* 要提交的下一個 sector */
sector_t hard_sector; /* 要完成的下一個 sector */
unsigned long nr_sectors; /* 剩余需要提交的 sector 數(shù) */
unsigned long hard_nr_sectors; /*剩余需要完成的 sector 數(shù)*/
/* 在當(dāng)前 segment 中剩余的需提交的 sector 數(shù) */
unsigned int current_nr_sectors;

/*在當(dāng)前 segment 中剩余的需完成的 sector 數(shù) */
unsigned int hard_cur_sectors;

struct bio *bio;
struct bio *biotail;

struct hlist_node hash;
union {
struct rb_node rb_node; /* sort/lookup */
void *completion_data;
};

/*
* I/O 調(diào)度器可獲得的兩個指針,如果需要更多,請動態(tài)分配 
*/
void *elevator_private;
void *elevator_private2;

struct gendisk *rq_disk;
unsigned long start_time;

/* scatter-gather DMA 方式下 addr+len 對的數(shù)量(執(zhí)行物理地址合并后)
*/
unsigned short nr_phys_segments;

unsigned short ioprio;

void *special;
char *buffer;

int tag;
int errors;

int ref_count;

unsigned short cmd_len;
unsigned char __cmd[BLK_MAX_CDB];
unsigned char *cmd;

unsigned int data_len;
unsigned int extra_len;
unsigned int sense_len;
void *data;
void *sense;

unsigned long deadline;
struct list_head timeout_list;
unsigned int timeout;
int retries;

/*
* 完成回調(diào)函數(shù)
*/
rq_end_io_fn *end_io;
void *end_io_data;

struct request *next_rq;

};


3)請求隊列初始化:

  3.1:請求隊列數(shù)據(jù)結(jié)構(gòu)
  3.2:request_queue_t *blk_init_queue(request_fn_proc *rfn, spinlock_t *lock)
第一個參數(shù)是指向"請求處理函數(shù)"的指針,該函數(shù)直接和硬盤打交道,用來處理數(shù)據(jù)在內(nèi)存和硬盤之間的傳輸。該函數(shù)整體的作用就是為了分配請求隊列,并初始化。
(3)-3:typedef void (request_fn_proc)(struct reqest_queue *q)
該函數(shù)作為上述函數(shù)(request_queue_t *blk_init_queue(request_fn_proc *rfn,spinlock_t *lock))的參數(shù),主要作用就是處理請求隊列中的bio,完成數(shù)據(jù)在內(nèi)存和硬盤之間的傳遞。(注意:該函數(shù)參數(shù)中的bio都是經(jīng)過i/o調(diào)度器的
(3)-4:typedef int (make_request_fn)(struct request_queue *q,struct bio *bio)
該函數(shù)是的第一個參數(shù)是請求隊列,第二個參數(shù)是bio,該函數(shù)的作用是根據(jù)bio生成一個request(所以叫制造請求函數(shù))。
注意:在想不使用I/O調(diào)度器的時候,就應(yīng)該在該函數(shù)中實現(xiàn),對每一傳入該函數(shù)的bio之間進行處理,完成數(shù)據(jù)在內(nèi)存和硬盤的之間的傳輸,這樣就可以不使用"request_fn_proc"函數(shù)了。(所以可以看出來,如果使用i/o調(diào)度器,make_request_fn函數(shù)是在request_fn_proc函數(shù)之前執(zhí)行)
<I/O調(diào)度器的使用與否>
a:背景
------I/O調(diào)度器看起來可以提高訪問速度,但是這是并不是最快的,因為I/O調(diào)度過程會花費很多時間。最快的方式就是不使用I/O調(diào)度器
b:請求隊列和I/O調(diào)度器
------要脫離I/O調(diào)度器,就必須了解請求隊列request_queue,因為I/O調(diào)度器和請求隊列是綁定在一起的。其關(guān)系如下:
 如山圖所示,請求隊列request_queue 中的elevator指針式指向I/O調(diào)度函數(shù)的。
b:通用塊層函數(shù)調(diào)用關(guān)系(對bio的處理過程)
b-1:調(diào)用框圖
 
b-2:具體分析
(1)當(dāng)需要讀寫一個數(shù)據(jù)的時候,通用塊層,會根據(jù)用戶空間的請求,生成一個bio結(jié)構(gòu)體。
(2)準(zhǔn)備好bio后,會調(diào)用函數(shù)generic_make_request()函數(shù),函數(shù)原形如下:
void generic_make_request(struct bio *bio)
(3)該函數(shù)會調(diào)用底層函數(shù):
static inline void _generic_make_request(struct bio *bio);
(4)到這里會分層兩種情況:
第一種,調(diào)用請求隊列中自己定義的make_request_fn()函數(shù),那問題來了,系統(tǒng)怎么知道這個自己定義函數(shù)在哪里呢?由內(nèi)核函數(shù)blk_queue_make_request()函數(shù)指定,函數(shù)原形:
void blk_queue_make_request(struct request_queue *q,make_request_fn *mfn);
第二種,使用請求隊列中系統(tǒng)默認__make_request()函數(shù),函數(shù)原形“
static int __make_request(struct request_queue *q,struct bio *bio);
該函數(shù)會啟動I/O調(diào)度器,對bio進行調(diào)度處理,bio結(jié)構(gòu)或被合并到請求隊列的一個請求結(jié)構(gòu)的request中。最后調(diào)用request_fn_proc()將數(shù)據(jù)寫入或讀出塊塊設(shè)備。
c:使用I/O調(diào)度器和不使用I/O調(diào)度器
c-1:不使用i/o調(diào)度器(blk_alloc_queue())
bio的流程完全由驅(qū)動開發(fā)人員控制,要達到這個目的,必須使用函數(shù)blk_alloc_queue()來申請請求隊列,然后使用函數(shù)blk_queue_make_requset()給bio指定具有request_fn_proc()功能的函數(shù)Virtual_blkdev_make_request來完成數(shù)據(jù)在內(nèi)存和硬盤之間的傳輸(該函數(shù)本來是用來將bio加入request中的)。
static int Virtual_blkdev_make_request(struct requset_queue *q,structb bio *bio)
{
   //因為不使用I/O調(diào)度算法,直接在該函數(shù)中完成數(shù)據(jù)在內(nèi)存和硬盤之間的數(shù)據(jù)傳輸,該函數(shù)
   //代替了request_fn_proc()函數(shù)的功能
   ............
}
Virtual_blkdev_queue = blk_alloc_queue(GFP_KERNEL)
if(!Virtual_blkdev_queue)
{
   ret=-ENOMEN;
   goto err_alloc_queue;
}
blk_queue_make_request(Virtual_blkdev_queue,Virtual_blkdev_make_request);
c-2:使用i/o調(diào)度器(blk_init_queue())
bio先經(jīng)過__make_request()函數(shù),I/O調(diào)度器,和request_fn_proc()完成內(nèi)存和硬盤之間的數(shù)據(jù)傳輸。該過程使用函數(shù)blk_init_queue()函數(shù)完成隊列的初始化,并指定request_fn_proc():
struct request_queue* blk_inti_queue(request_fn_proc *rfn,spinlock_t *lock)

<總結(jié)驅(qū)動框架>
 a:塊設(shè)備驅(qū)動加載過程
(1)使用alloc_disk()函數(shù)分配通用磁盤gendisk的結(jié)構(gòu)體。
(2)通過內(nèi)核函數(shù)register_blkdev()函數(shù)注冊設(shè)備,該過程是一個可選過程。
   (也可以不用注冊設(shè)備,驅(qū)動一樣可以工作,該函數(shù)和字符設(shè)備的register_chrdev()函數(shù)相對應(yīng),對于大多數(shù)的塊設(shè)備,第一個工作就是相內(nèi)核注冊自己,但是在Linux2.6以后,register_blkdev()函數(shù)的調(diào)用變得可選,內(nèi)核中register_blkdev()函數(shù)的功能正在逐漸減少。基本上就只有如下作用:
)分局major分配一個塊設(shè)備號
)在/proc/devices中新增加一行數(shù)據(jù),表示塊設(shè)備的信息
(3)根據(jù)是否需要I/O調(diào)度,將情況分為兩種情況,一種是使用請求隊列進行數(shù)據(jù)傳輸,一種是不使用請求隊列進行數(shù)據(jù)傳輸。
(4)初始化gendisk結(jié)構(gòu)體的數(shù)據(jù)成員,包括major,fops,queue等賦初值。
(5)使用add_disk()函數(shù)激活磁盤設(shè)備(當(dāng)調(diào)用該函數(shù)后就可以對磁盤進行操作(訪問),所以調(diào)用該函數(shù)之前必須所有的準(zhǔn)備工作就緒)
b:塊設(shè)備驅(qū)動卸載過程
(1)使用del_gendisk()函數(shù)刪除gendisk設(shè)備,并使用put_disk()刪除對gendisk設(shè)備的引用;
(2)使用blk_clean_queue()函數(shù)清楚請求隊列,并釋放請求隊列所占用的資源。
(3)如果在模塊加載函數(shù)中使用register_blkdev()注冊設(shè)備,那么就需要調(diào)用unregister_blkdev()函數(shù)注銷設(shè)備并釋放對設(shè)備的引用。
<塊設(shè)備驅(qū)動代碼示例(不使用I/O調(diào)度器)>
制造請求函數(shù)(在這里完成數(shù)據(jù)的讀寫)
卸載函數(shù)
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
[快速上手Linux設(shè)備驅(qū)動]之塊設(shè)備驅(qū)動流程詳解一
linux內(nèi)核分析筆記----塊I/O層
harddisk
Linux塊設(shè)備層分析(1)
Linux文件系統(tǒng)之文件的讀寫(續(xù)二)
宋寶華:Linux文件讀寫(BIO)波瀾壯闊的一生
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服