1. 程式人生 > 其它 >device mapper原理(轉載)

device mapper原理(轉載)

&emsp Device Mapper 是 Linux2.6 核心中支援邏輯卷管理的通用裝置對映機制,它為實現用於儲存資源管理的塊裝置驅動提供了一個高度模組化的核心架構,如圖 1。

&emsp 圖1 Device Mapper的核心體系架構

&emsp 在核心中它通過一個一個模組化的 target driver 外掛實現對 IO 請求的過濾或者重新定向等工作,當前已經實現的 target driver 外掛包括軟 raid、軟加密、邏輯卷條帶、多路徑、映象、快照等,圖中 linear、mirror、snapshot、multipath 表示的就是這些 target driver。Device mapper 進一步體現了在 Linux 核心設計中策略和機制分離的原則,將所有與策略相關的工作放到使用者空間完成,核心中主要提供完成這些策略所需要的機制。Device mapper 使用者空間相關部分主要負責配置具體的策略和控制邏輯,比如邏輯裝置和哪些物理裝置建立對映,怎麼建立這些對映關係等等,而具體過濾和重定向 IO 請求的工作由核心中相關程式碼完成。因此整個 device mapper 機制由兩部分組成–核心空間的 device mapper 驅動、使用者空間的device mapper 庫以及它提供的 dmsetup 工具。在下文中,我們分核心和使用者空間兩部分進行介紹。

核心部分

&emsp Device mapper 的核心相關程式碼已經作為 Linux 2.6 核心釋出版的一部分整合到核心原始碼中了,相關程式碼在核心原始碼的 driver/md/ 目錄中,其程式碼檔案可以劃分為實現 device mapper 核心中基本架構的檔案和實現具體對映工作的 target driver 外掛檔案兩部分。文章下面的分析結果主要是基於上述原始碼檔案得到的。

重要概念

&emsp Device mapper 在核心中作為一個塊裝置驅動被註冊的,它包含三個重要的物件概念,mapped device、對映表、target device。Mapped device 是一個邏輯抽象,可以理解成為核心向外提供的邏輯裝置,它通過對映表描述的對映關係和 target device 建立對映。從 Mapped device 到一個 target device 的對映表由一個多元組表示,該多元組由表示 mapped device 邏輯的起始地址、範圍、和表示在 target device 所在物理裝置的地址偏移量以及target 型別等變數組成(這些地址和偏移量都是以磁碟的扇區為單位的,即 512 個位元組大小)。

&emsp Target device 表示的是 mapped device 所對映的物理空間段,對 mapped device 所表示的邏輯裝置來說,就是該邏輯裝置對映到的一個物理裝置。Device mapper 中這三個物件和 target driver 外掛一起構成了一個可迭代的裝置樹。在該樹型結構中的頂層根節點是最終作為邏輯裝置向外提供的 mapped device,葉子節點是 target device 所表示的底層物理裝置。最小的裝置樹由單個 mapped device 和 target device 組成。每個 target device 都是被mapped device 獨佔的,只能被一個 mapped device 使用。一個 mapped device 可以對映到一個或者多個 target device 上,而一個 mapped device 又可以作為它上層 mapped device的 target device 被使用,該層次在理論上可以在 device mapper 架構下無限迭代下去。

&emsp 圖2 Device mapper 核心中各物件的層次關係

&emsp 在圖2 中我們可以看到 mapped device1 通過對映表和 a、b、c 三個 target device 建立了對映關係,而 target device a 又是通過 mapped device 2 演化過來,mapped device 2 通過對映表和 target device d 建立對映關係。

&emsp 我們進一步看一下上述三個物件在程式碼中的具體實現,dm.c 檔案定義的 mapped_device 結構用於表示 mapped device,它主要包括該 mapped device 相關的鎖,註冊的請求佇列和一些記憶體池以及指向它所對應對映表的指標等域。Mapped device 對應的對映表是由 dm_table.c 檔案中定義的 dm_table 結構表示的,該結構中包含一個 dm_target結構陣列,dm_target 結構具體描述了 mapped_device 到它某個 target device 的對映關係。而在 dm_table 結構中將這些 dm_target 按照 B 樹的方式組織起來方便 IO 請求對映時的查詢操作。Dm_target 結構具體記錄該結構對應 target device 所對映的 mapped device 邏輯區域的開始地址和範圍,同時還包含指向具體 target device 相關操作的 target_type 結構的指標。Target_type 結構主要包含了 target device 對應的 target driver 外掛的名字、定義的構建和刪除該型別target device的方法、該類target device對應的IO請求重對映和結束IO的方法等。而表示具體的target device的域是dm_target中的private域,該指標指向mapped device所對映的具體target device對應的結構。表示target device的具體結構由於不同的target 型別而不同,比如最簡單的線性對映target型別對應target device的結構是dm-linear.c檔案中定義的linear_c結構。其定義如下:

struct linear_c {
    struct dm_dev *dev;
    sector_t start;
};

該target device的定義相當簡單,就只包括了表示對應物理裝置的dm_dev結構指標和在該物理裝置中以扇區為單位的偏移地址start。上述幾個資料結構關係如圖3所示:

&emsp 圖3 device mapper中幾個重要資料結構的關係

核心中建立過程

&emsp 在下面我們結合具體的程式碼簡要介紹下在核心中建立一個mapped device的過程:

  1. 根據核心向用戶空間提供的ioctl 介面傳來的引數,用dm-ioctl.c檔案中的dev_create函式建立相應的mapped device結構。這個過程很簡單,主要是向核心申請必要的記憶體資源,包括mapped device和為進行IO操作預申請的記憶體池,通過核心提供的blk_queue_make_request函式註冊該mapped device對應的請求佇列dm_request。並將該mapped device作為磁碟塊設備註冊到核心中。
  2. 呼叫dm_hash_insert將建立好的mapped device插入到device mapper中的一個全域性hash表中,該表中儲存了核心中當前建立的所有mapped device。
  3. 使用者空間命令通過ioctl呼叫table_load函式,該函式根據使用者空間傳來的引數構建指定mapped device的對映表和所對映的target device。該函式先構建相應的dm_table、dm_target結構,再呼叫dm-table.c中的dm_table_add_target函式根據使用者傳入的引數初始化這些結構,並且根據引數所指定的target型別,呼叫相應的target型別的構建函式ctr在記憶體中構建target device對應的結構,然後再根據所建立的dm_target結構更新dm_table中維護的B樹。上述過程完畢後,再將建立好的dm_table新增到mapped device的全域性hash表對應的hash_cell結構中。
  4. 最後通過ioctl呼叫do_resume函式建立mapped device和對映表之間的繫結關係,事實上該過程就是通過dm_swap_table函式將當前dm_table結構指標值賦予mapped_device相應的map域中,然後再修改mapped_device表示當前狀態的域。

通過上述的4個主要步驟,device mapper在核心中就建立一個可以提供給使用者使用的mapped device邏輯塊裝置。

IO流

&emsp Device mapper本質功能就是根據對映關係和target driver描述的IO處理規則,將IO請求從邏輯裝置mapped device轉發相應的target device上。Device mapper處理所有從核心中塊一級IO子系統的generic_make_request和submit_bio介面[兩個介面具體的描述可以檢視參考文獻[1]和[2],這兩本書對核心中的塊IO層有比較詳盡的講解。] 中定向到mapped device的所有塊讀寫IO請求。IO請求在device mapper的裝置樹中通過請求轉發從上到下地進行處理。當一個bio請求在裝置樹中的mapped deivce向下層轉發時,一個或者多個bio的克隆被建立併發送給下層target device。然後相同的過程在裝置樹的每一個層次上重複,只要裝置樹足夠大理論上這種轉發過程可以無限進行下去。在裝置樹上某個層次中,target driver結束某個bio請求後,將表示結束該bio請求的事件上報給它上層的mapped device,該過程在各個層次上進行直到該事件最終上傳到根mapped device的為止,然後device mapper結束根mapped device上原始bio請求,結束整個IO請求過程。

&emsp Bio在device mapper的裝置樹進行逐層的轉發時,最終轉發到一個或多個葉子target節點終止。因為一個bio請求不可以跨多個target device(亦即物理空間段), 因此在每一個層次上,device mapper根據使用者預先告知的mapped device 的target對映資訊克隆一個或者多個bio,將bio進行拆分後轉發到對應的target device上。這些克隆的bio先交給mapped device上對應的target driver上進行處理,根據target driver中定義的IO處理規則進行IO請求的過濾等處理,然後再提交給target device完成。上述過程在dm.c檔案中的dm_request函式中完成。Target driver可以對這些bio做如下處理:

&emsp 1. 將這些bio在本驅動內部排隊等待以後進行處理;
&emsp 2. 將bio重新定向到一個或多個target device上或者每個target device上的不同扇區;
&emsp 3. 向device mapper返回error 狀態。

IO請求就按照上文中描述的過程在圖2中所示的裝置樹中逐層進行處理,直到IO請求結束。

小結

&emsp Device mapper在核心中向外提供了一個從邏輯裝置到物理裝置的對映架構,只要使用者在使用者空間制定好對映策略,按照自己的需要編寫處理具體IO請求的target driver外掛,就可以很方便的實現一個類似LVM的邏輯卷管理器。Device mapper以ioctl的方式向外提供介面,使用者通過使用者空間的device mapper庫,向device mapper的字元裝置傳送ioctl命令,完成向內的通訊。它還通過ioctl提供嚮往的事件通知機制,允許target driver將IO相關的某些事件傳送到使用者空間。

使用者空間部分

&emsp Device mapper在使用者空間相對簡單,主要包括device mapper庫和dmsetup工具。Device mapper庫就是對ioctl、使用者空間建立刪除device mapper邏輯裝置所需必要操作的封裝,dmsetup是一個提供給使用者直接可用的建立刪除device mapper裝置的命令列工具。因為它們的功能和流程相對簡單,在本文中對它們的細節就不介紹了,使用者空間主要負責如下工作:

  1. 發現每個mapped device相關的target device;
  2. 根據配置資訊建立對映表;
  3. 將使用者空間構建好的對映表傳入核心,讓核心構建該mapped device對應的dm_table結構;
  4. 儲存當前的對映資訊,以便未來重新構建。

&emsp 以下我們主要通過例項來說明dmsetup的使用,同時進一步說明device mapper這種對映機制。使用者空間中最主要的工作就是構建並儲存對映表,下面給出一些對映表的例子:

1)
0    1024  linear /dev/sda 204
1024 512   linear /dev/sdb 766
1536 128   linear /dev/sdc 0
 
2)  
0   2048    striped 2   64  /dev/sda    1024    /dev/sdb    0
 
3)  
0   4711    mirror  core    2   64  nosync  2   /dev/sda    2048    /dev/sdb 1024

&emsp 例子1中將邏輯裝置01023扇區、10241535扇區以及1536~1663三個地址範圍分別以線形對映的方式對映到/dev/sda裝置第204號扇區、/dev/sdb裝置第766號扇區和/dev/sdc裝置的第0號扇區開始的區域。

&emsp 例子2中將邏輯裝置從0號扇區開始的,長度為2048個扇區的段以條帶的方式對映的到/dev/sda裝置的第1024號扇區以及/dev/sdb裝置的第0號扇區開始的區域。同時告訴核心這個條帶型別的target driver存在2個條帶裝置與邏輯裝置做對映,並且條帶的大小是64個扇區,使得驅動可以該值來拆分跨裝置的IO請求。

&emsp 例子3中將邏輯裝置從0號扇區開始的,長度為4711個扇區的段以映象的方式對映到/dev/sda裝置的第2048個扇區以及/dev/sdb裝置的第1024號扇區開始的區域。

&emsp 對映表確定後,建立、刪除邏輯裝置的操作就相對簡單,通過dmsetup如下命令就可以完成相應的操作。

dmsetup create 裝置名 對映表文件    /* 根據指定的對映表建立一個邏輯裝置 */
 
dmsetup reload  裝置名 對映表文件 /*    為指定裝置從磁碟中讀取對映檔案,重新構建對映關係    */
 
dmsetup remove  裝置名 /* 刪除指定的邏輯裝置 */

&emsp 圖4 根據例子1中對映表在核心中建立的邏輯裝置

&emsp 當用戶空間根據對映表下達建立邏輯裝置命令後,device mapper在核心中就根據傳入的引數和對映關係建立邏輯地址到實體地址的對映關係。根據對映表例子1中的對映關係建立的裝置如圖4所示,圖中的下半部分就抽象地描繪出了按照該對映表在核心中建立的邏輯地址到實體地址的對映關係。

&emsp Device mapper的使用者空間部分對開發者要實現自己的儲存管理工具來說是可選的,事實上,很多我們常見的邏輯卷管理器,比如LVM2、dmraid等工具都利用device mapper的提供的device mapper使用者空間庫,根據自己的管理需求建立獨立的一套管理工具,而並沒有使用它提供的dmsetup工具,甚至IBM的開源專案企業級的邏輯卷管理系統-EVMS,在實現中都沒有采用device mapper的使用者空間庫,完全根據核心中的ioctl定義實現了一套自己的函式庫。

Target Driver

&emsp Device mapper提供了一個統一的架構,通過target driver 外掛的方式允許使用者根據實際的需要指定自己的IO處理規則,因此target driver充分體現了device mapper的靈活性。在上文中我們已經不止一次的提到過target driver,也描述過target driver的功能,在這裡我們結合最簡單的linear target driver具體介紹target driver的實現。

Target driver主要定義對IO請求的處理規則,在device mapper中對target driver的操作已定義好了統一的介面,在實現中該介面由我們上文提到的target_type結構中定義,它定義了以下target driver的方法:

  1. 構建target device 的方法;
  2. 刪除target device 的方法;
  3. Target的對映IO請求的方法;
  4. Target結束IO請求的方法;
  5. 暫停target device讀寫的方法;
  6. 恢復target device讀寫的訪問;
  7. 獲取當前target device狀態的訪問;
  8. Target 處理使用者訊息的方法;

&emsp 使用者可以根據具體需求選擇性地實現上述方法,但一般最少要實現前3種方法,否則在device mapper下不能夠正常的工作。linear target driver就只實現了前3種方法和方法7,它完成邏輯地址空間到實體地址空間的線性對映,可以將多個物理裝置以線性連線的方式組成一個邏輯裝置,就如圖4中描述的那樣,通過linear target driver將/dev/sda、/dev/sdb、/dev/sdc的三段連續空間組成了一個大的邏輯塊裝置。Linear target的實現很簡單,它的建立和刪除方法主要完成申請和釋放描述linear target device所用結構的記憶體資源;IO對映處理方法的實現更是簡單,如下程式碼所示:

static int linear_map(struct dm_target *ti, struct bio *bio,
              union map_info *map_context)
{
    struct linear_c *lc = (struct linear_c *) ti->private;
 
    bio->bi_bdev = lc->dev->bdev;
    bio->bi_sector = lc->start + (bio->bi_sector - ti->begin);
 
    return 1;
}

&emsp 該對映方法就是將傳送給邏輯裝置mapped device的bio請求,根據對映關係以線性的方式重新定向到linear target device所表示物理裝置的相應位置,如程式碼所示具體實現方法就是修改bio的bi_bdev裝置指標為target device對應的裝置指標,並根據target device的起始地址和該bio請求在mapped device裝置上的偏移值改變IO請求開始的扇區號bi_sector,從而完成IO請求的重定向。其他target driver的實現也都大同小異,按照device mapper所定義的介面規範,結合自己需要的功能進行實現即可,這裡就不一一介紹了,有興趣的讀者可以看核心中具體的target driver程式碼。

總結

&emsp Device Mapper是Linux作業系統中塊裝置一級提供的一種主要對映機制,現在已被多數Linux下的邏輯卷管理器所採用。在該機制下,實現使用者自定義的儲存資源管理策略變得極其方便。理解device mapper所提供的對映機制,也是進一步理解Linux下一些常見邏輯卷管理器實現的基礎。

永遠年輕,永遠熱淚盈眶