前面用無請求佇列實現的ramdisk
的驅動程式雖然申請了請求佇列,但實際上沒用上,因為
ramdisk
不像實際的磁碟訪問速度慢需要快取,
ramdisk
之間使用記憶體空間,所以就沒用請求佇列了。本文將介紹使用請求佇列的
ramdisk
驅動,雖然對於
ramdisk
使用請求佇列用處不大,但對於基於磁碟的塊裝置驅動來說卻是必須要用的。
在ldd3
書中,其中的有些塊裝置操作函式在當前的linux版本中有了很大的變動,需要自己重新根據新定義的一些函式進行適當的移植,以解決編譯時報出的各種錯誤,主要是在請求處理函式中修改。
在前面用無請求佇列實現的ramdisk
的驅動程式中直接用
blk_alloc_queue
來分配請求佇列,這樣分配的請求佇列是沒有請求處理函式的,之所以可以這樣是因為當時就沒有使用請求佇列,來自上層的請求都被自定義的請求提交函式處理了。現在如果要使用請求佇列,那麼就必須要對請求佇列初始化其請求處理函式,核心提供了函式
blk_init_queue
,該函式以自定義的請求函式位址作為引數傳來被呼叫,它既實現了
blk_alloc_queue
的功能,還初始化了佇列的請求處理函式和請求提交函式,其中請求提交函式設定為通用函式
blk_queue_bio
。這樣來自上層的請求通過請求佇列被分發到我們自定義的請求處理函式來處理。
1//分配乙個請求佇列
2 simp_blkdev_queue =blk_init_queue(simp_blkdev_do_request, null);
3if(!simp_blkdev_queue)
4
上面的simp_blkdev_do_request
為自定義的請求處理函式。
請求處理函式實現類似於在無請求佇列ramdisk
驅動中提交請求函式,說白了它們都是對上層請求的處理,只不過前者處理的是多個
bio鍊錶(每個請求時乙個
bio鍊錶),後者僅僅處理乙個
bio而已。我們只需要遍歷每個
bio鍊錶中的每個
bio,並根據當前請求的型別來做相應的處理就可以了。值得注意的是自2.6.31核心開始,一些函式發生變化(見linux/include/blkdev.h
)。在2.6.32
核心中,
request -> sectors 變為 blk_rq_pos(request)
request -> nr_sectors 變為 blk_rq_nr_sectors(request)
elv_next_request(request) 變為 blk_fetch_request(request)
end_request(request, error) 變為 __blk_end_request_all(req, err))
1static
void simp_blkdev_do_request(struct request_queue *q)221
//獲取需要操作的記憶體位置
22 disk_mem = simp_blkdev_data + (blk_rq_pos(req) << 9
);23
switch (rq_data_dir(req))
3233
/*memcpy(req->buffer,
34simp_blkdev_data + (blk_rq_pos(req) << 9),
35blk_rq_cur_bytes(req));
*/36 __blk_end_request_all(req, 0
);37
break;38
case
write:
39rq_for_each_segment(bvec, req, ri)
4046
/*memcpy(simp_blkdev_data + (blk_rq_pos(req) << 9),
47req->buffer, blk_rq_cur_bytes(req));
*/48 __blk_end_request_all(req, 0
);49
break;50
default:51
/*no default because rq_data_dir(req) is 1 bit
*/52
break;53
}54}55 }
需要注意的是結束請求需要用__blk_end_request_all函式,不能使用blk_end_request_all,這兩個函式的唯一區別就是前者不會去獲取佇列鎖,後者會嘗試獲取佇列鎖,用後者會導致系統死鎖,並是系統崩潰(反正開始我是崩潰了幾次)。上面**中的rq_for_each_segment是用來遍歷乙個請求中的所有segment,和bio_for_each_segment類似。
編寫簡單的ramdisk(選擇IO排程器)
目前linux 中包含anticipatory cfq deadline 和noop這4 個i o 排程器。2.6.18 之前的linux 預設使用 anticipatory 而之後的預設使用 cfq。我們在前面 編寫簡單的ramdisk 有請求佇列 中分配請求佇列使用了blk init queue...
列印所有請求的過濾器
slf4j webfilter value filtername aloggingfilter 攔截所有的請求,名字隨便取乙個 configuration public class loggingfilterconfig implements filter override public void ...
編寫簡單的makefile
假如有乙個上百個檔案的 構成的專案,如果只是對其中乙個或少數幾個檔案進行了修改,若用gcc編譯工具就不得不把整個專案裡的檔案重新編譯一遍。編譯過程分為編譯 彙編鏈結等階段。其中,編譯階段僅檢查語法錯誤以及函式與變數的宣告是否正確,在鏈結階段則主要完成函式鏈結和全域性變數的鏈結。因此,沒有改動的源 根...