以記憶體作為儲存介質,在無佇列模式下實現的乙個簡單塊裝置驅動程式,在最新的linux3.3.7測試可用。
塊裝置驅動編寫的主要過程:
1.註冊塊裝置驅動
register_blkdev 可以申請獲得主裝置號;
2.設計自己裝置對應的資料結構
**裡面的mybd_info結構,便於管理裝置資訊,這個資料機構裡面的data,是通過vmalloc申請的一塊記憶體,用於存放塊裝置的資料,這個資料結構不是標準塊裝置驅動必須的;
3.初始化請求佇列和請求處理函式
請求佇列中的請求處理函式的作用是截獲塊裝置上的io請求,在無佇列模式下,每乙個io請求以bio結構的形式作為引數傳入請求處理函式,請求佇列和請求處理函式的初始化過程可以通過blk_alloc_queue和blk_queue_make_request實現。在無佇列模式下,請求佇列僅僅是請求處理函式的載體,沒實質性作用;
4.申請並初始化gendisk結構
乙個gendisk結構對應乙個塊裝置或者塊裝置上的分割槽,通過alloc_disk可以申請乙個gendisk結構,內部很多資料需要自己初始化;
5.註冊塊裝置
所有初始化工作完成後,向系統註冊塊裝置,通過add_disk實現。至此,塊裝置驅動的初始化工作已經完成;成功的話該塊裝置可以在/dev目錄下檢視到;
6.登出塊裝置驅動和相關資料結構
根據初始化工作的逆過程進行登出和釋放記憶體。
總結一下:乙個塊裝置驅動先要註冊才能獲得主裝置號,塊裝置驅動在核心中對應乙個gendisk結構,gendisk結構包含塊裝置幾乎所有的資訊,另外,每個塊裝置驅動都要申請乙個請求佇列(包含乙個請求處理函式),請求處理函式以引數的形式自動接受到bio結構(包含一次io操作的資訊),然後通過分析bio結構進行相應io操作。
具體**如下:
#include #include #include #include #include #include module_license("dual bsd/gpl");
#define need_debug
#ifdef need_debug
#define my_debug(fmt, args...) printk(kern_debug "from my_bd: " fmt, ##args)
#else
#define my_debug(fmt, args...)
#endif
#define bdname "my_bd"
#define max_bd_minor 1
#define max_bd_size_in_mb 32
#define max_bd_size (2*1024*max_bd_size_in_mb) //單位為扇區
#define sector_shift 9
#define sector_size 512
extern struct request_queue *blk_alloc_queue(gfp_t gfp_mask);
extern void blk_queue_make_request(struct request_queue *q, make_request_fn *mfn);
struct mybd_info
;struct mybd_info *mybd = null;
struct block_device_operations mybd_fop;
static void free_bd_info()
}static void mydb_make_request(struct request_queue *q, struct bio *bio)
dsk_offset += bio_cur_bytes(bio); //執行下乙個bio_vec對應的io操作前,重新計算該bio_vec對應的資料在塊裝置上的偏移
}bio_endio(bio, 0); //bio對應的io操作結束時呼叫bio_endio
return;
}static int __init mybd_init(void)
//init mybd_info, which contains the information of our block device
mybd = (struct mybd_info *)kmalloc(sizeof(struct mybd_info), gfp_kernel);
if(mybd == null)
my_debug("major = %d\n", major);
//init mybd
memset(mybd, 0, sizeof(struct mybd_info));
mybd->size = max_bd_size; //size的單位是扇區512byte
mybd->data = (void *)vmalloc(mybd->sizespin_lock_init(&mybd->lock); //初始化自旋鎖
//init request queue
mybd->queue = blk_alloc_queue(gfp_kernel); //申請請求佇列
if(!mybd->queue)
goto out_blk_alloc_queue;
blk_queue_make_request(mybd->queue, mydb_make_request); //繫結請求佇列和請求處理函式
//alloc and init gendisk
mybd->gd = alloc_disk(max_bd_minor); //申請gendisk結構
if (!mybd->gd)
strcpy(mybd->gd->disk_name, bdname); //dbname就是/dev/中顯示的塊裝置名稱
mybd->gd->major = major; //裝置驅動申請的主裝置號和gendisk繫結
mybd->gd->first_minor = 0; //第乙個此裝置號
mybd->gd->fops = &mybd_fop; //通過block_device_operations結構中方法來處理對該塊裝置的控制和操作
mybd->gd->queue = mybd->queue; //把請求佇列和gendisk繫結
set_capacity(mybd->gd, mybd->size); //設定塊裝置的容量
//register block device driver, tell the os that there is a new block device
add_disk(mybd->gd);
return 0;
out:
my_debug("out!\n");
return -1;
out_malloc_mybd:
my_debug("out_malloc_mybd!\n");
free_bd_info();
unregister_blkdev(major, bdname);
return -1;
out_blk_alloc_queue:
my_debug("out_blk_alloc_queue!\n");
out_alloc_disk:
my_debug("out_alloc_disk!\n");
blk_cleanup_queue(mybd->queue);
free_bd_info();
unregister_blkdev(major, bdname);
return -1;
}static void __exit mybd_exit(void)
module_init(mybd_init);
module_exit(mybd_exit);
Linux塊裝置驅動
塊裝置提供塊裝置提供裝置的訪問,裝置的訪問,可以隨機的以固定大小的塊傳輸資料,例如我們最為常見的磁碟裝置,當然塊裝置和字元裝置有較大差別,塊裝置有自己的驅動介面。簡單來說,核心決定乙個塊是固定的4096 位元組,當然該值可以隨著依賴檔案系統的變化而改變。塊裝置驅動採用register blkdev向...
linux驅動之塊裝置驅動
塊裝置驅動的系統架構 塊裝置註冊過程 1,註冊裝置塊驅動程式 register blkdev 2,初始化請求佇列 blk init queue 3,指明扇區的大小 blk queue logical block size dev queue,sect size 4,申請乙個gendisk結構,初始化...
LINUX塊裝置驅動 1
編寫塊裝置驅動的關鍵步驟 1 呼叫register blkdev申請或註冊主裝置號及裝置名稱,詳見核心原始碼中該函式的注釋。不過下面這篇文章裡並未用到這一步 2 呼叫blk init queue函式建立並初始化乙個 request queue 結構,該函式需要乙個用來處理請求的do request函...