Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

Linux 區塊裝置驅動開發詳解:架構、請求佇列與 RAMDISK 實作

編輯:Linux 教學

區塊裝置驅動比字元裝置複雜得多,涉及緩衝區管理、I/O 排程、請求佇列等核心機制。本文系統剖析 Linux 區塊裝置驅動架構、關鍵資料結構(block_device_operations、gendisk)、模組載入/卸載、open/release/ioctl、請求佇列處理流程,並以 RAMDISK 為實戰範例。

一、區塊裝置 vs 字元裝置 I/O 差異

特性字元裝置區塊裝置
存取單位位元組固定大小區塊(通常 512 bytes)
緩衝機制通常無緩衝,直接讀寫有緩衝區,可調整請求順序
存取模式循序隨機存取
效能優化無合併相鄰請求、電梯演算法

針對機械硬碟,重新排序請求(如 1→10→3→2 調整為 1→2→3→10)可大幅減少磁頭移動;但 SSD/RAMDISK 無機械延遲,排序效益有限。

二、核心資料結構

1. block_device_operations


struct block_device_operations {
    int (*open)(struct inode *, struct file *);
    int (*release)(struct inode *, struct file *);
    int (*ioctl)(struct inode *, struct file *, unsigned, unsigned long);
    long (*unlocked_ioctl)(struct file *, unsigned, unsigned long);
    long (*compat_ioctl)(struct file *, unsigned, unsigned long);
    int (*direct_access)(struct block_device *, sector_t, unsigned long *);
    int (*media_changed)(struct gendisk *);      // 可移動媒體偵測
    int (*revalidate_disk)(struct gendisk *);    // 媒體變更後重新驗證
    int (*getgeo)(struct block_device *, struct hd_geometry *); // 磁碟幾何資訊
    struct module *owner;
};

2. gendisk(通用磁碟)


struct gendisk {
    int major;              // 主裝置號
    int first_minor;        // 起始次裝置號
    int minors;             // 最大次裝置數(不可分區則為 1)
    char disk_name[32];     // 裝置名稱
    struct hd_struct **part; // 分區資訊
    struct block_device_operations *fops;
    struct request_queue *queue;  // 請求佇列指標
    void *private_data;     // 私有資料
    sector_t capacity;      // 容量(以 512-byte sector 為單位)
    // ... 其他欄位
};

同一磁碟的各分區共享 major,minor 不同。queue 是核心管理 I/O 請求的核心。

三、模組載入/卸載、open/release/ioctl

  • 載入時:分配 gendisk、設定 fops、queue、capacity、呼叫 add_disk()
  • 卸載時:del_gendisk()、put_disk()、釋放請求佇列
  • open/release:檢查媒體狀態、模組計數器
  • ioctl:核心區塊層已處理大部分標準命令,驅動通常只需處理廠商特定命令

四、請求佇列——區塊裝置驅動核心

request_queue 管理所有 I/O 請求,驅動需實作 request_fn 處理請求:


static void my_request_fn(struct request_queue *q) {
    struct request *req;
    while ((req = blk_fetch_request(q)) != NULL) {
        // 處理 req->cmd_type == REQ_TYPE_FS 的讀寫請求
        // 完成後呼叫 blk_end_request(req, 0, blk_rq_bytes(req));
    }
}

關鍵 API:blk_init_queue()、blk_cleanup_queue()、blk_fetch_request()、blk_end_request()、blk_queue_logical_block_size()。

五、完整讀寫流程

  1. 用戶發起 read()/write()
  2. VFS 轉換為 bio 結構
  3. 通用區塊層合併相鄰 bio 形成 request
  4. 請求放入 request_queue,觸發 request_fn
  5. 驅動處理請求,完成後呼叫 blk_end_request()
  6. 核心喚醒等待進程,回傳結果

六、RAMDISK 實作範例

RAMDISK 將記憶體模擬為區塊裝置,無機械延遲,適合學習區塊驅動基本框架。核心步驟:

  1. 分配記憶體陣列作為儲存媒體
  2. 實作 request_fn 直接在記憶體間 memcpy
  3. 註冊 gendisk、設定 capacity、queue
  4. 支援分區表讀取(getgeo)

完整程式碼請參考核心原始碼 drivers/block/brd.c。

Copyright © Windows教程網 All Rights Reserved