韋東山老師幫我們把框架搭建起來了,我們先來看一下:
框架:
--------------------------------------------- 檔案的讀寫
檔案系統: vfat, ext2, ext3, yaffs2, jffs2 (把檔案的讀寫轉換為扇區的讀寫)
-----------------ll_rw_block----------------- 扇區的讀寫
1. 把"讀寫"放入佇列
2. 呼叫佇列的處理函式(優化/調順序/合併)
塊裝置驅動程式
---------------------------------------------
硬體: 硬碟,flash
我們在來囉嗦一下:在應用程式對檔案的讀寫通過具體的檔案系統被轉換為對扇區的讀寫,對扇區的讀寫呼叫的是ll_rw_block這個函式,對扇區進行讀寫的時候會根據某種排程進行優化,之後通過塊裝置驅動程
序來訪問具體的硬體。
那麼到底是不是這個樣子呢?閒話少說,來看源**:
由於我們主要關心核心而不是檔案系統,所以我們從
ll_rw_block函式開始分析
ll_rw_block(int rw, int nr, struct buffer_head *bhs)
for (i = 0; i < nr; i++) //提交資料
struct bio *bio; // bio即block input/output,接下來根據bh來構造bio
bio->bi_size = bh->b_size;//這是乙個例子
submit_bio(rw, bio);//提交bio
generic_make_request(bio);// 通用的構造請求: 使用bio來構造請求(request)
__generic_make_request(bio);
q = bdev_get_queue(bio->bi_bdev);// 找到佇列
ret = q->make_request_fn(q, bio);//呼叫q中的構造請求函式,詳見注釋1
__make_request;//上面的那條**實際上是執行這個函式
elv_merge(q, &req, bio);//先嘗試將bio合併到請求佇列中的某個請求中
req = get_request_wait(q, rw_flags, bio);//如果無法將bio合併到某一請求,就會構造乙個請求
init_request_from_bio(req, bio);//根據bio初始化這個請求
add_request(q, req);//把請求放入佇列 ,這裡採用的電梯排程演算法,詳見注釋2
__generic_unplug_device(q);//在適當的時候處理佇列裡面的請求,這個有核心決定
q->request_fn(q);//呼叫佇列的"處理函式,我們猜想他應該在裝置驅動程式裡 //面被設定
上面就是讀寫塊裝置的流程框架了,由於本人比較笨,所以還得再來羅嗦一遍它的流程:
首先應用程式裡面用讀寫函式讀寫檔案,通過檔案系統呼叫
ll_rw_block函式,在這個函式裡會根據傳遞進來的資料構造出來乙個塊裝置輸入輸出結構體。然後先試圖將這個結構體合併到塊裝置的請求佇列中的某乙個請求中,如果如法合併的話,就會根據這個結構體構造出來乙個新的請求,然後根據電梯排程演算法將這個請求加入到請求佇列中去。
之後核心在適當的時候會根據佇列裡面的處理函式來處理佇列裡面的請求。由此我們也可以猜測出來我們的驅動程式裡面需要做的事情了:應用程式裡面讀寫塊裝置的時候會將請求放入塊裝置佇列裡面,我們要處理請求的話當然是要在塊裝置驅動程式裡面為塊裝置分配乙個佇列,然後初始化它,最主要的不要忘記佇列處理函式。
注釋1:
q->make_request_fn是預設的函式,我們在核心中搜尋過程如下:
首先我們發現
q->make_request_fn在下面這個函式裡被設定:
void blk_queue_make_request(request_queue_t * q, make_request_fn * mfn)
那麼mfn這個函式是什麼東西呢?要想知道需要搜尋誰呼叫了
blk_queue_make_request
blk_init_queue_node(request_fn_proc *rfn, spinlock_t *lock, int node_id)
終於我們找到了這個預設函式
__make_request,也就是說
ret = q->make_request_fn(q, bio);這調**實際上是執行
__make_request這個函式。
注釋2:
電梯排程演算法:我們先來說一說電梯是怎樣工作的。當電梯上的時候,如果在電梯所在層的上層和下層都有請求的話,電梯會先處理上層的請求,同樣當電梯下的時候如果上層下層都有請求的話,電梯會先處理下層的請求。那麼我們這裡電梯排程演算法也是採用如此的策略,比如當讀資料的時候,如果有讀請求也有寫請求,那麼要先處理讀請求。在寫資料的時候,如果有讀請求也有寫請求,那麼先處理寫請求。
裝置驅動 塊裝置驅動程式
塊裝置驅動程式提供對面向塊的裝置的訪問,這種裝置以隨機訪問的方式傳輸資料,並且資料總是具有固定大小的塊。典型的塊裝置是磁碟驅動器,也有其它型別的塊裝置。塊裝置和字元裝置有很大區別。比如塊裝置上可以掛載檔案系統,字元裝置不可以。這是隨機訪問帶來的優勢,因為檔案系統需要能按塊儲存資料,同時更需要能隨機讀...
塊裝置驅動程式
裝置描述 定義於linux genhd.h struct gendisk 裝置註冊 void add disk struct gendisk gd 裝置操作 字元裝置通過file operations結構來定義它所支援的操作。塊裝置通過struct block device operations結構...
塊裝置驅動程式
塊裝置驅動程式 1 塊裝置和字元裝置的區別 1,讀取資料的單元不同,塊裝置讀寫資料的基本單元式塊,字元裝置的基本單元是位元組。2,塊裝置可以隨機訪問,字元裝置只能順序訪問。2 linux核心中塊裝置的描述 struct gendisk 裝置操作 struct block device operati...