1. 程式人生 > >塊裝置層bdev程式設計簡介

塊裝置層bdev程式設計簡介

介紹

塊裝置是支援以固定大小的塊讀取和寫入資料的儲存裝置。這些塊通常為512或4096位元組。裝置可以是軟體中的邏輯構造,或者對應於諸如NVMe SSD的物理裝置。

塊裝置層包含單個通用庫lib/bdev,以及實現各種型別的塊裝置的許多可選模組(作為單獨的庫)。通用庫的公共標頭檔案是bdev.h,它是與任何型別的塊裝置互動所需的全部API。下面將介紹如何使用該API與bdev進行互動。有關實現bdev模組的指南,請參閱編寫自定義塊裝置模組

除了為所有塊裝置提供通用抽象之外,bdev層還提供了許多有用的功能:

  • 響應佇列滿或記憶體不足的情況自動排隊I / O請求
  • 支援熱移除,即使在I / O流量發生時也是如此。
  • I / O統計資訊,如頻寬和延遲
  • 裝置重置支援,和I / O超時跟蹤

基本原語

bdev API的使用者與許多基本物件進行互動。

struct spdk_bdev,本指南將其稱為bdev,表示通用塊裝置。struct spdk_bdev_desc,此前稱為描述符,表示給定塊裝置的控制代碼。描述符用於建立和跟蹤使用底層塊裝置的許可權,非常類似於UNIX系統上的檔案描述符。對塊裝置的請求是非同步的,由spdk_bdev_io物件表示請求必須在關聯的I / O通道上提交。訊息傳遞和併發中描述了I / O通道的動機和設計

Bdev可以是分層的,這樣一些bdev通過將請求路由到其他bdev來服務I / O. 

這可用於實現快取,RAID,邏輯卷管理等。的BDEV該路線I / O到其他的BDEV通常被稱為虛擬的BDEV,或vbdevs的簡稱。

初始化庫

bdev層依賴於標頭檔案include / io_channel.h抽象的通用訊息傳遞基礎結構。有關完整說明,請參閱訊息傳遞和併發最重要的是,只能通過呼叫spdk_allocate_thread()從已經分配了SPDK的執行緒呼叫bdev庫

從分配的執行緒中,可以通過呼叫spdk_bdev_initialize()來初始化bdev庫,這是一個非同步操作。在呼叫完成回撥之前,不能呼叫其他bdev庫函式。同樣,要拆除bdev庫,請呼叫spdk_bdev_finish()

發現塊裝置

所有塊裝置都有一個簡單的字串名稱。在任何時候,都可以通過呼叫spdk_bdev_get_by_name()來獲取指向裝置物件的指標,或者可以使用spdk_bdev_first()spdk_bdev_next()及其變體來迭代整個bdev集

一些塊裝置也可以給出別名,也是字串名稱。別名的行為類似於符號連結 - 它們可以與實名互換使用以查詢塊裝置。

準備使用塊裝置

為了將I / O請求傳送到塊裝置,必須首先通過呼叫spdk_bdev_open()來開啟它這將返回一個描述符。多個使用者可能同時開啟bdev,並且使用者之間的讀寫協調必須由bdev層之外的某些更高級別的機制來處理。如果虛擬bdev模組宣告了bdev,則開啟具有寫入許可權的bdev可能會失敗虛擬bdev模組實現RAID或邏輯卷管理之類的邏輯,並將其I / O轉發到較低級別的bdev,因此它們將這些較低級別的bdev標記為聲稱可防止外部使用者發出寫入。

開啟塊裝置時,可以提供可選的回撥和上下文,如果刪除了為塊裝置提供服務的底層儲存,則將呼叫該回調和上下文。例如,當NVMe SSD熱插拔時,將在物理NVMe SSD支援的bdev的每個開啟描述符上呼叫remove回撥。回撥可以被認為是關閉開啟描述符的請求,因此可以釋放其他記憶體。當存在開放描述符時,不能拆除bdev,因此強烈建議提供回撥。

當用戶完成描述符時,他們可以通過呼叫spdk_bdev_close()來釋放它

描述符可以同時傳遞給多個執行緒並從中使用。但是,對於每個執行緒,必須通過呼叫spdk_bdev_get_io_channel()獲得單獨的I / O通道這將分配必要的每執行緒資源,以便在不接受鎖定的情況下向bdev提交I / O請求。要釋放頻道,請呼叫spdk_put_io_channel()在銷燬所有相關通道之前,不能關閉描述符。

傳送I / O

一旦一個描述符和一個通道已經獲得,I / O可以通過呼叫各種I / O功能提交諸如傳送spdk_bdev_read() 這些呼叫都將回調作為引數,稍後將使用spdk_bdev_io物件的控制代碼呼叫該引數響應完成,使用者必須呼叫spdk_bdev_free_io()來釋放資源。在此回撥中,使用者還可以使用函式spdk_bdev_io_get_nvme_status()spdk_bdev_io_get_scsi_status()以他們選擇的格式獲取錯誤資訊。

通過呼叫spdk_bdev_read()spdk_bdev_write()等函式來執行I / O提交這些函式將一個指向記憶體區域的指標或一個描述將被傳輸到塊裝置的記憶體的分散集合列表作為引數。必須通過spdk_dma_malloc()或其變體分配此記憶體有關記憶體必須來自特殊分配池的完整說明,請參閱使用者空間驅動程式的記憶體管理在可能的情況下,記憶體中的資料將使用直接記憶體訪問直接傳輸到塊裝置這意味著它不會被複制。

所有I / O提交功能都是非同步和非阻塞的。它們不會因任何原因阻塞或停止執行緒。但是,I / O提交功能可能會以兩種方式之一失敗。首先,它們可能會立即失敗並返回錯誤程式碼。在這種情況下,將不會呼叫提供的回撥。其次,它們可能非同步失敗。在這種情況下,關聯的spdk_bdev_io將傳遞給回撥,它將報告錯誤資訊。

某些I / O請求型別是可選的,給定的bdev可能不支援。要查詢bdev以獲取其支援的I / O請求型別,請呼叫spdk_bdev_io_type_supported()

重置塊裝置

為了處理意外的故障情況,bdev庫提供了一種通過呼叫spdk_bdev_reset()來執行裝置重置的機制這會將訊息傳遞給bdev存在I / O通道的每個其他執行緒,暫停它,然後將重置請求轉發到底層bdev模組並等待完成。完成後,I / O通道將恢復,重置將完成。bdev模組中的特定行為是特定於模組的。例如,NVMe裝置將刪除所有佇列對,執行NVMe重置,然後重新建立佇列對並繼續。最重要的是,無論裝置型別如何,塊裝置的所有未完成的I / O都將在重置完成之前完成。