Linux塊裝置驅動的實現

2021-06-06 23:01:18 字數 4015 閱讀 3988

以記憶體作為儲存介質,在無佇列模式下實現的乙個簡單塊裝置驅動程式,在最新的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函...