1. 基本概念: 扇區(Sectors):任何塊設備硬體對數據處理的基本單位。通常,1個扇區的大小為512byte。(對設備而言) 塊 (Blocks):由Linux制定對內核或文件系統等數據處理的基本單位。通常,1個塊由1個或多個扇區組成。(對Linux操作系統而言) 段(Segments):由若 ...
1. 基本概念:
扇區(Sectors):任何塊設備硬體對數據處理的基本單位。通常,1個扇區的大小為512byte。(對設備而言)
塊 (Blocks):由Linux制定對內核或文件系統等數據處理的基本單位。通常,1個塊由1個或多個扇區組成。(對Linux操作系統而言)
段(Segments):由若幹個相鄰的塊組成。是Linux記憶體管理機制中一個記憶體頁或者記憶體頁的一部分。
2. 塊設備結構體:
1 static const struct block_device_operations blk_ops = { 2 .owner = THIS_MODULE, 3 .open = blk_open, 4 .release = blk_release, 5 };
3. 創建塊設備:
3.1靜態創建(主設備號自己定義)
register_blkdev(MAJOR,"z-block");
3.2 動態創建(內核自動分配主設備號)
major = register_blkdev(0,"z-block");
4. 分配一個gendisk結構體,用來描述磁碟信息
blkdisk = alloc_disk(3);//磁碟分區數,次設備個數 = 分區數 + 1
5. 創建隊列
內核驅動訪問塊設備,進行輸入輸出操作,都需要發送請求。但有些磁碟請求速度緩慢,影響了讀寫速度,所以引入了隊列。採用電梯演算法,先將請求放入隊列,優化後執行,提高了塊設備的訪問速度。
blk_queue = blk_init_queue(do_request, &blk_spin);
其中第一個參數是隊列的處理函數,第二個參數是隊列訪問許可權的自旋鎖。定義如下
static DEFINE_SPINLOCK(blk_spin);
6. 將隊列告訴gendisk結構體
blkdisk->queue = blk_queue;
7. 確定主、次設備號及操作函數
blkdisk->first_minor = 0;
blkdisk->major = major;
sprintf(blkdisk->disk_name, "zblock");
blkdisk->fops = &blk_ops;
註意這裡不加sprintf這句話,最後insmod會出錯。具體原因我也還不知道。
8. 定義配磁碟容量(大小)
set_capacity(blkdisk, SIZE);//設置扇區數
9. 分配一塊空間,作為源/目的
block_buf = kzalloc(BUFFERSIZE, GFP_KERNEL); //分配一塊空間,作為源/目的
10. 向內核註冊gendisk結構體
add_disk(blkdisk);
11. 請求隊列處理函數
11.1 while迴圈使用elv_next_request()獲取申請隊列中每個未處理的申請,這是Linux2.6.22.6里的函數,對於linux3.4.2內核,應該使用blk_fetch_request函數;
11.2 使用rq_data_dir()來獲取每個申請的讀寫命令標誌,為 0(READ)表示讀, 為1(WRITE)表示寫;
11.3 使用memcp()來讀或者寫扇區(緩存);
11.4 linux2.6使用end_request()來結束獲取的每個申請,linux3.4.2使用函數__blk_end_request_cur;
12. 磁碟格式化
/mnt # mkdosfs /dev/zblock
13. 掛載磁碟
/mnt # mount /dev/zblock tmp/
在tmp/目錄下寫數據,實際上寫到了塊設備/dev/zblock裡面。cat /dev/zblock > /tmp/zblock.bin就可以將/dev/zblock里的數據傳到/tmp/zblock.bin。
完整程式見https://www.cnblogs.com/zhu-g5may/p/9314403.html